# 遞迴模式比對Recursive Pattern Matching

## 詳細設計Detailed design

### 為運算式Is Expression

is系統會擴充運算子，以根據 模式 來測試運算式。The is operator is extended to test an expression against a pattern.

relational_expression
: is_pattern_expression
;
is_pattern_expression
: relational_expression 'is' pattern
;


### 模式Patterns

is_pattern 運算子、 switch_statement 中，以及 switch_expression 中使用模式來表示資料的圖形，而這些資料 (我們呼叫輸入值) 要進行比較。Patterns are used in the is_pattern operator, in a switch_statement, and in a switch_expression to express the shape of data against which incoming data (which we call the input value) is to be compared. 模式可能是遞迴的，因此資料的部分可能會與子模式進行比對。Patterns may be recursive so that parts of the data may be matched against sub-patterns.

pattern
: declaration_pattern
| constant_pattern
| var_pattern
| positional_pattern
| property_pattern
;
declaration_pattern
: type simple_designation
;
constant_pattern
: constant_expression
;
var_pattern
: 'var' designation
;
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern
| subpattern ',' subpatterns
;
subpattern
: pattern
| identifier ':' pattern
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
property_pattern
: type? property_subpattern simple_designation?
;
simple_designation
: single_variable_designation
;
: '_'
;


#### 宣告模式Declaration Pattern

declaration_pattern
: type simple_designation
;


Declaration_pattern 會測試運算式是否為指定的型別，並在測試成功時將它轉換成該型別。The declaration_pattern both tests that an expression is of a given type and casts it to that type if the test succeeds. 如果指定是 single_variable_designation，這可能會導入給定識別碼所命名之指定類型的本機變數。This may introduce a local variable of the given type named by the given identifier, if the designation is a single_variable_designation. 當模式比對作業的結果為時，就會 明確地指派 該本機變數 trueThat local variable is definitely assigned when the result of the pattern-matching operation is true.

var v = expr as Type;
if (v != null) { // code using v


if (expr is Type v) { // code using v


int? x = 3;
if (x is int v) { // code using v


#### 常數模式Constant Pattern

constant_pattern
: constant_expression
;


e is null在新撰寫的程式碼中，我們預期會看到最常見的測試方法 null ，因為它無法叫用使用者定義的程式碼 operator==We expect to see e is null as the most common way to test for null in newly written code, as it cannot invoke a user-defined operator==.

#### Var 模式Var Pattern

var_pattern
: 'var' designation
;
designation
: simple_designation
| tuple_designation
;
simple_designation
: single_variable_designation
;
single_variable_designation
: identifier
;
: _
;
tuple_designation
: '(' designations? ')'
;
designations
: designation
| designations ',' designation
;


discard_pattern
: '_'
;


#### 位置模式Positional Pattern

positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern
| subpattern ',' subpatterns
;
subpattern
: pattern
| identifier ':' pattern
;


• 如果省略 別，且輸入值的型別是元組型別，則 subpatterns 的數目必須和元組的基數相同。If type was omitted and the input value's type is a tuple type, then the number of subpatterns is required to be the same as the cardinality of the tuple. 每個元組元素都會與相對應的子 模式 進行比對，而如果全部成功，則比對成功。Each tuple element is matched against the corresponding subpattern, and the match succeeds if all of these succeed. 如果有任何子 模式 具有 識別碼，則必須將元組元素命名為元組類型中的對應位置。If any subpattern has an identifier, then that must name a tuple element at the corresponding position in the tuple type.
• 否則，如果適合以 Deconstruct 類型 的成員的形式存在，則如果輸入值的類型與 類型相容，就會發生編譯時期錯誤。Otherwise, if a suitable Deconstruct exists as a member of type, it is a compile-time error if the type of the input value is not pattern-compatible with type. 在執行時間，輸入值會針對 類型 進行測試。At runtime the input value is tested against type. 如果失敗，則位置模式比對會失敗。If this fails then the positional pattern match fails. 如果成功，則會將輸入值轉換成這個類型，並 Deconstruct 使用全新編譯器產生的變數來叫用來接收 out 參數。If it succeeds, the input value is converted to this type and Deconstruct is invoked with fresh compiler-generated variables to receive the out parameters. 收到的每個值會與相對應的子 模式 進行比對，而如果全部成功，則比對成功。Each value that was received is matched against the corresponding subpattern, and the match succeeds if all of these succeed. 如果有任何子 模式 具有 識別碼，則必須將參數命名于對應的位置 DeconstructIf any subpattern has an identifier, then that must name a parameter at the corresponding position of Deconstruct.
• 如果省略了 類型 ，而且輸入值的類型是 objectITuple 可由隱含參考轉換轉換成的類型， ITuple 而且 subpatterns 中不會出現任何 識別碼 ，則會使用進行比對 ITupleOtherwise if type was omitted, and the input value is of type object or ITuple or some type that can be converted to ITuple by an implicit reference conversion, and no identifier appears among the subpatterns, then we match using ITuple.
• 否則，模式會是編譯時期錯誤。Otherwise the pattern is a compile-time error.

##### 範例Example

    var newState = (GetState(), action, hasKey) switch {
(DoorState.Closed, Action.Open, _) => DoorState.Opened,
(DoorState.Opened, Action.Close, _) => DoorState.Closed,
(DoorState.Closed, Action.Lock, true) => DoorState.Locked,
(DoorState.Locked, Action.Unlock, true) => DoorState.Closed,
(var state, _, _) => state };


#### 屬性模式Property Pattern

property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;


if (s is object o) ... // o is of type object
if (s is string x) ... // x is of type string
if (s is {} x) ... // x is of type string
if (s is {}) ...


##### 範例Example
if (o is string { Length: 5 } s)


### Switch 運算式Switch Expression

C # 語言語法會透過下列語法的生產增強：The C# language syntax is augmented with the following syntactic productions:

multiplicative_expression
: switch_expression
| multiplicative_expression '*' switch_expression
| multiplicative_expression '/' switch_expression
| multiplicative_expression '%' switch_expression
;
switch_expression
: range_expression 'switch' '{' '}'
| range_expression 'switch' '{' switch_expression_arms ','? '}'
;
switch_expression_arms
: switch_expression_arm
| switch_expression_arms ',' switch_expression_arm
;
switch_expression_arm
: pattern case_guard? '=>' expression
;
case_guard
: 'when' null_coalescing_expression
;


Switch_expression 的型別是在 switch_expression_arm s 的 token 右邊出現的 最常見運算式類型 => （如果這類型別存在），而且 switch 運算式的每個 arm 中的運算式都可以隱含地轉換成該型別。The type of the switch_expression is the best common type of the expressions appearing to the right of the => tokens of the switch_expression_arm s if such a type exists and the expression in every arm of the switch expression can be implicitly converted to that type. 此外，我們還新增了一個新的 switch expression 轉換，這是從 switch 運算式預先定義的隱含轉換，以及從 T 每個 arm 的運算式隱含轉換到的每個類型 TIn addition, we add a new switch expression conversion, which is a predefined implicit conversion from a switch expression to every type T for which there exists an implicit conversion from each arm's expression to T.

### 在元組常值上切換時的選擇性括弧Optional parens when switching on a tuple literal

switch ((a, b))
{


switch (a, b)
{