Delen via


Lijstpatronen

Notitie

Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.

Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. Deze verschillen worden vastgelegd in de relevante LDM-notities (Taalontwerpvergadering).

Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.

Kampioensprobleem: https://github.com/dotnet/csharplang/issues/3435

Samenvatting

Hiermee kunt u een matrix of een lijst vergelijken met een reeks patronen, bijvoorbeeld array is [1, 2, 3] overeenkomt met een gehele matrix van de lengte drie met respectievelijk 1, 2, 3 als elementen.

Gedetailleerd ontwerp

De syntaxis van het patroon wordt als volgt gewijzigd:

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
  ;

Er zijn twee nieuwe patronen:

  • De list_pattern wordt gebruikt om elementen te vergelijken.
  • Een slice_pattern is maar één keer toegestaan en slechts rechtstreeks in een list_pattern_clause en negeert nul of meer elementen.

Patrooncompatibiliteit

Een list_pattern is compatibel met elk type dat kan worden geteld, evenals indexeerbare. Het heeft een toegankelijke indexeerfunctie die een Index als argument of anderszins een toegankelijke indexeerfunctie met één int parameter gebruikt. Als beide indexeerfuncties aanwezig zijn, heeft de eerste voorkeur.

Een slice_pattern met een subpatroon is compatibel met elk type dat telbaar is, evenals segmenteerbaar— het heeft een toegankelijke indexeerder die een Range als argument gebruikt of anders een toegankelijke Slice methode met twee int parameters. Als beide aanwezig zijn, heeft de eerste voorkeur.

Een slice_pattern zonder subpatroon is compatibel met elk type dat compatibel is met een list_pattern.

Deze set regels is afgeleid van het bereikindexeerpatroon.

Subsumptiecontrole

Subsumptiecontrole werkt net als positionele patronen met ITuple: overeenkomende subpatronen worden op positie gematcht, plus een extra knooppunt voor het testen van de lengte.

De volgende code produceert bijvoorbeeld een fout omdat beide patronen dezelfde DAG opleveren:

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

In tegenstelling tot

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

De volgorde waarin subpatronen tijdens runtime worden vergeleken, is niet opgegeven en een mislukte overeenkomst probeert mogelijk niet alle subpatronen te vinden.

Met een specifieke lengte kunnen twee subpatronen naar hetzelfde element verwijzen. In dat geval wordt een test voor deze waarde ingevoegd in de beslissing DAG.

  • [_, >0, ..] or [.., <=0, _] wordt bijvoorbeeld length >= 2 && ([1] > 0 || length == 3 || [^2] <= 0) waarbij de lengtewaarde van 3 de andere test impliceert.
  • Omgekeerd wordt [_, >0, ..] and [.., <=0, _]length >= 2 && [1] > 0 && length != 3 && [^2] <= 0 waar de lengtewaarde van 3 de andere test niet toestaat.

Als gevolg hiervan wordt er een fout gegenereerd voor iets als case [.., p]: case [p]:, omdat we tijdens uitvoertijd hetzelfde element in het tweede geval vergelijken.

Als een slice-subpatroon overeenkomt met een lijst of een lengtewaarde, worden subpatronen behandeld alsof ze een directe subpatroon van de lijst zijn. [..[1, 2, 3]] omvat bijvoorbeeld een patroon in de vorm van [1, 2, 3].

De volgende veronderstellingen worden gedaan voor de leden die worden gebruikt:

  • De eigenschap die het type aftelbaar maakt, wordt verondersteld altijd een niet-negatieve waarde te retourneren, als en alleen als het type indexeerbaar is. Het patroon { Length: -1 } kan bijvoorbeeld nooit overeenkomen met een matrix.
  • Het lid dat het type segmenteerbaar maakt wordt verondersteld goed te gedragen, dat wil zeggen, de retourwaarde is nooit nul en dat het een juiste deelsnede van de bevattende lijst is.

Het gedrag van een patroonkoppelingsbewerking is niet gedefinieerd als een van de bovenstaande aannames niet wordt vastgehouden.

Verlaging

Een patroon van het formulier expr is [1, 2, 3] is gelijk aan de volgende 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

Een slice_pattern functioneert als een echte 'discard'; er worden geen tests uitgevoerd voor een dergelijk patroon, maar het beïnvloedt uitsluitend andere knooppunten, namelijk de lengte en de indexeerder. Een patroon van het formulier expr is [1, .. var s, 3] is bijvoorbeeld gelijk aan de volgende code (indien compatibel via expliciete Index en Range ondersteuning):

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

Het invoertype voor de slice_pattern is het retourtype van de onderliggende this[Range] of Slice methode met twee uitzonderingen: voor respectievelijk string en matrices worden string.Substring en RuntimeHelpers.GetSubArray gebruikt.

Niet-opgeloste vragen

  1. Moeten we multidimensionale matrices ondersteunen? (antwoord [LDM 2021-05-26]: niet ondersteund. Als we een algemene MD-matrix-gerichte release willen maken, willen we teruggaan naar alle gebieden die ze momenteel missen, niet alleen lijstpatronen.)
  2. Moeten we een algemeen patroon accepteren na .. in een slice_pattern? (antwoord [LDM 2021-05-26]: Ja, elk patroon is toegestaan na een segment.)
  3. Met deze definitie test het patroon [..] voor expr.Length >= 0. Moeten we deze test weglaten, ervan uitgaande dat Length altijd niet negatief is? (antwoord [LDM 2021-05-26]: [..] zal geen lengtecontrole uitvoeren)