Freigeben über


Listenmuster

Anmerkung

Dieser Artikel ist eine Featurespezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.

Es kann einige Abweichungen zwischen der Featurespezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den entsprechenden Hinweisen zum Language Design Meeting (LDM) erfasst.

Weitere Informationen zum Einführen von Featurespezifikationen in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.

Champion Issue: https://github.com/dotnet/csharplang/issues/3435

Zusammenfassung

Hiermit können Sie ein Array oder eine Liste mit einer Abfolge von Mustern abgleichen, z. B. array is [1, 2, 3] entspricht einem ganzzahligen Array der Länge 3 mit 1, 2, 3 als Elemente.

Detailentwurf

Die Mustersyntax wird wie folgt geändert:

list_pattern_clause
  : '[' (pattern (',' pattern)* ','?)? ']'
  ;

list_pattern
  : list_pattern_clause simple_designation?
  ;

slice_pattern
  : '..' pattern?
  ;

primary_pattern
  : list_pattern
  | slice_pattern
  | // all of the pattern forms previously defined
  ;

Es gibt zwei neue Muster:

  • Die list_pattern wird verwendet, um Elemente abzugleichen.
  • Ein slice_pattern ist nur einmal und nur direkt in einer list_pattern_clause erlaubt und verwirft null oder mehr Elemente.

Musterkompatibilität

Ein list_pattern ist mit jedem Typ kompatibel, der zählbar sowie indizierbar ist - es hat einen zugänglichen Indexer, der ein Index als Argument annimmt oder andernfalls einen zugänglichen Indexer mit einem einzelnen int Parameter. Wenn beide Indexer vorhanden sind, wird der frühere bevorzugt.

Ein slice_pattern mit einem Subpattern ist mit jedem Typ kompatibel, der zählbar sowie teilbar ist - es hat einen zugänglichen Indexer, der ein Range als Argument nimmt oder andernfalls eine zugängliche Slice Methode mit zwei int Parametern. Wenn beide vorhanden sind, wird der frühere bevorzugt.

Ein Slice_pattern ohne ein Subpattern ist mit jedem Typ kompatibel, der mit einem list_pattern kompatibel ist.

Dieser Satz von Regeln wird vom Bereichsindexermusterabgeleitet.

Subsumptionsprüfung

Die Subsumptionsprüfung funktioniert genau wie Positionsmuster mit ITuple - entsprechende Untermuster werden nach Position plus einem zusätzlichen Knoten zur Prüfung der Länge abgeglichen.

Der folgende Code erzeugt beispielsweise einen Fehler, da beide Muster dieselbe DAG liefern:

case [_, .., 1]: // expr.Length is >= 2 && expr[^1] is 1
case [.., _, 1]: // expr.Length is >= 2 && expr[^1] is 1

Anders als:

case [_, 1, ..]: // expr.Length is >= 2 && expr[1] is 1
case [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1

Die Reihenfolge, in der Untermuster zur Laufzeit abgeglichen werden, ist nicht angegeben, und bei einem fehlgeschlagenen Abgleich wird möglicherweise nicht versucht, alle Untermuster abzugleichen.

Angesichts einer bestimmten Länge ist es möglich, dass zwei Unterpattern auf dasselbe Element verweisen, in diesem Fall wird ein Test für diesen Wert in die Entscheidung DAG eingefügt.

  • Beispielsweise wird [_, >0, ..] or [.., <=0, _]length >= 2 && ([1] > 0 || length == 3 || [^2] <= 0), wobei der Längenwert von 3 den anderen Test impliziert.
  • Umgekehrt wird [_, >0, ..] and [.., <=0, _] zu length >= 2 && [1] > 0 && length != 3 && [^2] <= 0, wobei der Längenwert 3 den anderen Test nicht zulässt.

Infolgedessen wird für etwas wie case [.., p]: case [p]: ein Fehler erzeugt, weil wir zur Laufzeit im zweiten Fall auf dasselbe Element treffen.

Wenn ein Segmentunterpattern einer Liste oder einem Längenwert entspricht, werden Unterpattern behandelt, als wären sie eine direkte Unterpattern der enthaltenden Liste. Beispielsweise subsumiert [..[1, 2, 3]] ein Muster des Formulars [1, 2, 3].

Die folgenden Annahmen werden für die verwendeten Mitglieder gemacht:

  • Es wird angenommen, dass die Eigenschaft, die den Typ zählbar macht, immer einen nicht-negativen Wert zurückgibt, wenn und nur wenn der Typ indexierbar ist. Beispielsweise kann das Muster { Length: -1 } nie mit einem Array übereinstimmen.
  • Bei dem Mitglied, das den Typ teilbar macht, wird davon ausgegangen, dass es sich gut verhält, d.h. dass der Rückgabewert niemals Null ist und dass es sich um ein korrektes Teilstück der enthaltenen Liste handelt.

Das Verhalten eines Musterabgleichsvorgangs ist nicht definiert, wenn eine der oben genannten Annahmen nicht enthalten ist.

Reduzierung

Ein Muster des Formulars expr is [1, 2, 3] entspricht dem folgenden Code:

expr.Length is 3
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Index(1, fromEnd: false)] is 2
&& expr[new Index(2, fromEnd: false)] is 3

Ein Slice_pattern verhält sich wie ein richtiger Discard, d.h. es werden keine Tests für ein solches Pattern ausgegeben, sondern es wirkt sich nur auf andere Knoten aus, nämlich auf die Länge und den Indexer. Beispielsweise entspricht ein Muster des Formulars expr is [1, .. var s, 3] dem folgenden Code (wenn es über explizite Index und Range Unterstützung kompatibel ist):

expr.Length is >= 2
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))] is var s
&& expr[new Index(1, fromEnd: true)] is 3

Der Eingabetyp für das slice_pattern ist der Rückgabetyp der zugrundeliegenden this[Range] oder Slice Methode mit zwei Ausnahmen: Für string und Arrays wird string.Substring bzw. RuntimeHelpers.GetSubArray verwendet.

Ungelöste Fragen

  1. Sollten wir mehrdimensionale Arrays unterstützen? (Antwort [LDM 2021-05-26]: Nicht unterstützt. Wenn wir eine allgemeine, auf MD-Arrays fokussierte Version erstellen möchten, sollten wir alle Bereiche überarbeiten, in denen sie derzeit fehlen, nicht nur Listenmuster.)
  2. Sollen wir ein allgemeines Muster nach .. in einem slice_pattern akzeptieren? (Antwort [LDM 2021-05-26]: Ja, jedes Muster ist nach einem slice zugelassen.)
  3. Nach dieser Definition testet das Muster [..] auf expr.Length >= 0. Sollten wir diesen Test weglassen, vorausgesetzt, Length ist immer nicht negativ? (Antwort [LDM 2021-05-26]: [..] wird keine Längenprüfung auslösen)