Sdílet prostřednictvím


Vzory seznamů

Poznámka

Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.

Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v příslušných poznámkách schůzky o návrhu jazyka (LDM) .

Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .

Problém šampiona: https://github.com/dotnet/csharplang/issues/3435

Shrnutí

Umožňuje spárovat matici nebo seznam se sekvencí vzorů, například array is [1, 2, 3] bude odpovídat celočíselné matici s délkou 1, 2, 3 jako jejími prvky.

Podrobný návrh

Syntaxe vzoru se upraví následujícím způsobem:

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
  ;

Existují dva nové vzory:

  • Vzor seznamu se používá k porovnání prvků.
  • slice_pattern je povoleno pouze jednou a pouze přímo v rámci list_pattern_clause a vynechává nula nebo více prvků.

Kompatibilita vzorů

list_pattern je kompatibilní s libovolným typem, který je počitatelný, stejně jako indexovatelný — má přístupný indexer, který přebírá Index jako argument, nebo jinak přístupný indexer s jediným parametrem int. Pokud jsou oba indexery přítomny, je upřednostňovaný první indexer.

slice_pattern s podpatternem je kompatibilní s libovolným typem, který je počítatelný a krájetelný – má přístupný indexer, který přijímá Range jako argument, nebo jinak přístupnou metodu Slice se dvěma parametry int. Pokud jsou oba přítomny, je upřednostňovaný první.

slice_pattern bez dílčího vzoru je kompatibilní s každým typem kompatibilním s list_pattern.

Tato sada pravidel je odvozena ze vzoru indexeru rozsahu .

Kontrola subsumpce

Kontrola subsumpce funguje stejně jako poziční vzory s ITuple – odpovídající podvzory se shodují podle pozice a dalším uzlem pro ověření délky.

Například následující kód vytvoří chybu, protože oba vzory poskytují stejný DAG:

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

Na rozdíl od:

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

Pořadí, ve kterém se podvzorů shodují během zpracování, není specifikováno, a pokud dojde k neúspěšné shodě, nemusí se pokusit sladit všechny podvzorů.

Pokud vezmeme v úvahu specifickou délku, je možné, že dvě dílčí vzory odkazují na stejný prvek; v takovém případě se do rozhodovacího DAG vloží test této hodnoty.

  • Například [_, >0, ..] or [.., <=0, _] se stane length >= 2 && ([1] > 0 || length == 3 || [^2] <= 0), kde hodnota délky 3 znamená druhý test.
  • Naopak [_, >0, ..] and [.., <=0, _] se stane length >= 2 && [1] > 0 && length != 3 && [^2] <= 0, kde hodnota délky 3 zakáže druhý test.

Výsledkem je, že se pro něco jako case [.., p]: case [p]: vytvoří chyba, protože za běhu porovnáváme stejný prvek ve druhém případě.

Pokud podvzorec řezu odpovídá seznamu nebo hodnotě délky, jsou podvzorce považovány za přímé podvzorce seznamu, který je obsahuje. Například [..[1, 2, 3]] zahrnuje vzor ve formě [1, 2, 3].

Předpokládají se následující skutečnosti týkající se používaných členů:

  • Vlastnost, která dělá typ spočitatelným, je předpokládána, že vždy vrátí nezápornou hodnotu, a to jedině pokud je typ indexovatelný. Například vzor { Length: -1 } nemůže odpovídat poli.
  • Člen, který dělá typ řezatelným, je považován za dobře se chovajícího, to znamená, že návratová hodnota není nikdy null a jedná se o správný podřez obsahujícího seznamu.

Chování operace porovnávání vzorů není definováno, pokud se některé z výše uvedených předpokladů neudrží.

Snížení

Vzor formuláře expr is [1, 2, 3] odpovídá následujícímu kódu:

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

slice_pattern funguje jako běžné zahození, tj. pro takový vzor se nevygenerují žádné testy, ale ovlivní pouze jiné uzly, konkrétně délku a indexátor. Vzor formuláře expr is [1, .. var s, 3] je například ekvivalentní následujícímu kódu (pokud je kompatibilní prostřednictvím explicitní podpory Index a Range):

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

Vstupní typ pro slice_pattern je návratovým typem podkladové this[Range] nebo Slice metody se dvěma výjimkami: Pro string a pole se použijí string.Substring a RuntimeHelpers.GetSubArray.

Nevyřešené otázky

  1. Měli bychom podporovat vícerozměrná pole? (odpověď [LDM 2021-05-26]: Nepodporuje se. Pokud chceme vytvořit obecnou verzi zaměřenou na pole MD, chtěli bychom se znovu vrátit ke všem oblastem, které aktuálně chybí, nejen vzory seznamů.)
  2. Měli bychom přijmout obecný vzor , který následuje po .. v části s posloupností ? (odpověď [LDM 2021-05-26]: Ano, jakýkoli vzor je povolený po řezu.)
  3. Podle této definice vzor [..] testuje expr.Length >= 0. Měli bychom takový test vynechat, za předpokladu, že Length je vždy nezáporná? (odpověď [LDM 2021-05-26]: [..] nevyvolá kontrolu délky)