手記
この記事は機能仕様です。 仕様は、機能の設計ドキュメントとして機能します。 これには、提案された仕様の変更と、機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が最終決定され、現在の ECMA 仕様に組み込まれるまで公開されます。
機能の仕様と完成した実装の間には、いくつかの違いがある可能性があります。 これらの違いは、関連する 言語設計会議 (LDM) ノートでキャプチャされます。
機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。
チャンピオンの課題: https://github.com/dotnet/csharplang/issues/3435
概要
配列またはリストをパターンのシーケンスと一致させることができます。たとえば、array is [1, 2, 3]
は、それぞれ要素として 1、2、3 の長さ 3 の整数配列と一致します。
詳細な設計
パターン構文は次のように変更されます。
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
;
次の 2 つの新しいパターンがあります。
- list_pattern は、要素の照合に使用されます。
- slice_pattern は list_pattern_clause 内で直接一度だけ許可され、0 個以上の要素を破棄します。
パターンの互換性
list_pattern は、カウント可能 であり、かつ インデックス可能 な任意の型と互換性があります。これには、Index
を引数として取るアクセス可能なインデクサーがあること、または単一の int
パラメーターを持つアクセス可能なインデクサーが必要です。 両方のインデクサーが存在する場合は、前者が推奨されます。
サブパターンを持つ slice_pattern は、カウント可能かつスライス可能な任意の型と互換性があります。Range
を引数として受け取るアクセス可能なインデクサー、または 2 つの int
パラメーターを持つアクセス可能な Slice
メソッドがあります。 両方が存在する場合は、前者が好ましい。
サブパターンのない slice_pattern は、list_patternと互換性のある任意の型と互換性があります。
この一連のルールは、範囲インデクサー パターンから派生します。
包含チェック
包含チェックは ITuple
による位置パターンと同様に機能します。対応するサブパターンは、位置に加えて、長さをテストするための追加ノードによって照合されます。
たとえば、次のコードでは、両方のパターンで同じ DAG が生成されるため、エラーが発生します。
case [_, .., 1]: // expr.Length is >= 2 && expr[^1] is 1
case [.., _, 1]: // expr.Length is >= 2 && expr[^1] is 1
次とは異なり:
case [_, 1, ..]: // expr.Length is >= 2 && expr[1] is 1
case [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1
実行時にサブパターンが一致する順序は指定されておらず、失敗した一致はすべてのサブパターンとの一致を試みない場合があります。
特定の長さがある場合、2 つのサブパターンが同じ要素を参照している可能性があります。この場合、この値のテストがデシジョン DAG に挿入されます。
- たとえば、
[_, >0, ..] or [.., <=0, _]
がlength >= 2 && ([1] > 0 || length == 3 || [^2] <= 0)
に変わるとき、長さの値 3 がもう一方のテストを意味します。 - 逆に、
[_, >0, ..] and [.., <=0, _]
は、長さの値が3であるためにもう一方のテストができず、length >= 2 && [1] > 0 && length != 3 && [^2] <= 0
になります。
その結果、実行時に同じ要素と一致してしまうため、2 番目のケースでは case [.., p]: case [p]:
などに対してエラーが生成されます。
スライスサブパターンがリストまたは長さの値と一致する場合、サブパターンは、含まれるリストの直接サブパターンであるかのように扱われます。 たとえば、[..[1, 2, 3]]
は [1, 2, 3]
という形式のパターンを含みます。
使用されるメンバーに関して、次の前提条件が行われます。
- 型 カウント可能な を作成するプロパティは、型がインデックス可能な である場合にのみ、常に負以外の値返すと見なされます。 たとえば、パターン
{ Length: -1 }
は配列と一致できません。 - 型 スライス可能な を作成するメンバーは、適切に動作すると見なされます。つまり、戻り値が null になることがなく、それが含まれるリストの適切なサブスライスであると見なされます。
上記の前提条件のいずれかが保持されていない場合、パターン マッチング操作の動作は未定義です。
引き下げ
expr is [1, 2, 3]
フォームのパターンは、次のコードと同じです。
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 は適切な破棄のように機能します。つまり、そのようなパターンに対してテストは出力されません。むしろ、長さとインデクサーという他のノードにのみ影響します。 たとえば、expr is [1, .. var s, 3]
形式のパターンは、次のコードと同じです (明示的な Index
と 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
slice_pattern の 入力型 は、基になる this[Range]
または Slice
メソッドの戻り値の型であり、2 つの例外があります。string
と配列の場合は、それぞれ string.Substring
と RuntimeHelpers.GetSubArray
が使用されます。
未解決の質問
- 多次元配列をサポートする必要がありますか? (回答 [LDM 2021-05-26]: サポートされていません。MD 配列に重点を置いた一般的なリリースを作成する場合は、リスト パターンだけでなく、現在不足しているすべての領域を再検討したいと考えています)。
..
に続く一般的な パターン を slice_patternの中で受け入れるべきでしょうか? (回答 [LDM 2021-05-26]: はい、スライスの後に任意のパターンが許可されます)。- この定義では、パターン
[..]
expr.Length >= 0
をテストします。Length
が常に負でないと仮定して、このようなテストを省略する必要がありますか? (回答 [LDM 2021-05-26]:[..]
は長さチェックを出力しません)
C# feature specifications