清單模式
注意
本文是功能規格。 規格可作為功能的設計檔。 其中包含建議的規格變更,以及功能設計和開發期間所需的資訊。 這些文章會發佈,直到提議的規格變更完成並併併入目前的ECMA規格為止。
功能規格與已完成實作之間可能有一些差異。 這些差異已記錄在相關的 語言設計會議(LDM)備忘錄中。
冠軍問題:https://github.com/dotnet/csharplang/issues/3435
總結
可讓您比對陣列或清單與一連串的模式。例如,array is [1, 2, 3]
會比對一個包含元素 1、2、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
;
有兩個新的模式:
- list_pattern 用於匹配元素。
- slice_pattern 只允許一次,而且只能直接用在 list_pattern_clause 中,以捨棄 零個或多個 元素。
模式相容性
list_pattern 與任何 可計數 和 可索引 的類型相容,因為它具有可存取的索引器,可以接受一個 Index
作為參數,或具有單一 int
參數的可存取索引器。 如果兩個索引器都存在,則偏好使用前者。
具有子模式的 slice_pattern 與可計算 以及 可交叉分析 的任何類型相容,其具有可存取索引器,可存取的索引器會採用 Range
做為自變數,或是具有兩個 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
未指定運行時間中比對子模式的順序,且失敗的比對可能不會嘗試比對所有子模式。
假設有特定長度,有可能有兩個子模式參考相同的元素,在此情況下,此值的測試會插入決策 DAG 中。
- 例如,
[_, >0, ..] or [.., <=0, _]
會變成length >= 2 && ([1] > 0 || length == 3 || [^2] <= 0)
,其中長度值為 3 表示另一個測試。 - 相反地,
[_, >0, ..] and [.., <=0, _]
會變成length >= 2 && [1] > 0 && length != 3 && [^2] <= 0
,其中長度值為 3 不允許進行其他測試。
因此,會產生類似 case [.., p]: case [p]:
的錯誤,因為在執行期間,我們會在第二個案例中比對相同的元素。
如果分割子模式符合清單或長度值,這些子模式會被視為包含清單的直接子模式。 例如,[..[1, 2, 3]]
包含一種 [1, 2, 3]
形式的模式。
對使用中的成員作出的下列假設:
- 只有當型別是 可編製索引時,才假設類型 可計算 的屬性會一律回傳非負值。 例如,模式
{ Length: -1 }
永遠無法比對陣列。 - 假設使類型 可以分割 的成員運行良好,也就是說,返回值從不為空,而且它是所含清單的適當子片段。
如果上述任何假設未保留,模式比對作業的行為是未定義的。
降低
表單 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
方法的傳回 類型,但有兩個例外:針對 string
和陣列,將會分別使用 string.Substring
和 RuntimeHelpers.GetSubArray
。
未解決的問題
- 我們應該支援多維度陣列嗎? (回答 [LDM 2021-05-26]:不支援。如果我們想要建立以 MD-陣列為主的版本,我們會想要重新審視他們目前不足的所有方面,而不只是列表模式。)
- 我們應該接受一般 模式, 遵循 slice_pattern中的
..
? (回答 [LDM 2021-05-26]:是,切片後允許任何模式。) - 根據這個定義,模式
[..]
是測試expr.Length >= 0
的。 我們是否應該省略這類測試,假設Length
一律為非負數? (回答 [LDM 2021-05-26]:[..]
不會發出長度檢查訊號)