常數位串上的模式比對 Span<char>
注意
本文是功能規格。 規格可作為功能的設計檔。 其中包含建議的規格變更,以及功能設計和開發期間所需的資訊。 這些文章會發佈,直到提議的規格變更完成並併併入目前的ECMA規格為止。
功能規格與已完成實作之間可能有一些差異。 這些差異在相關的 語言設計會議記錄(LDM)中擷取。
總結
允許在常數字符串上進行 Span<char>
和 ReadOnlySpan<char>
的模式匹配。
動機
在許多情況下,為了提升效能,偏好使用 Span<char>
和 ReadOnlySpan<char>
而非字串。 此架構已新增許多新的 API,可讓您使用 ReadOnlySpan<char>
取代 string
。
字串上的常見操作是使用 switch 來測試它是否為特定值,而編譯程式會優化這類 switch。 不過,除了手動進行切換和優化,目前無法有效地在 ReadOnlySpan<char>
上執行相同的操作。
為了鼓勵採用 ReadOnlySpan<char>
,我們允許在常數 string
上進行 ReadOnlySpan<char>
的模式匹配,因此也允許在 switch 中使用。
static bool Is123(ReadOnlySpan<char> s)
{
return s is "123";
}
static bool IsABC(Span<char> s)
{
return s switch { "ABC" => true, _ => false };
}
詳細設計
我們會按照如下所示變更 規格 的常數模式(新增內容以粗體顯示):
假設模式輸入值
e
,以及常數模式P
(其轉換值為v
)。
- 如果 e 具有整數型別或列舉型別,或是其中一種可為 Null 的形式,且 v 具有整數型別,則模式
P
會比對值,e,如果表達式e == v
的結果true
則為 :否則- 如果 e 的類型為
System.Span<char>
或System.ReadOnlySpan<char>
,而 c c 是常數位符串 ,而 c 沒有常數值null
,則如果System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c))
傳回true
,則模式會視為相符。- 當
object.Equals(e, v)
返回true
時,模式P
會比對 和 及 的值。
已知成員
System.Span<T>
和 System.ReadOnlySpan<T>
會根據名稱進行匹配,必須是 ref struct
s,而且可以在 corlib 外部定義。
System.MemoryExtensions
會依名稱被比對,而且可以在 corlib 外部定義。
System.MemoryExtensions.SequenceEqual
多載的簽章必須相符:
public static bool SequenceEqual<T>(System.Span<T>, System.ReadOnlySpan<T>)
public static bool SequenceEqual<T>(System.ReadOnlySpan<T>, System.ReadOnlySpan<T>)
System.MemoryExtensions.AsSpan
的簽章必須符合要求:
public static System.ReadOnlySpan<char> AsSpan(string)
選擇性參數的方法會從考慮中排除。
缺點
沒有
替代方案
沒有
未解決的問題
比對是否應該獨立於
MemoryExtensions.SequenceEqual()
等進行定義?如果
e
中所有字元都具有e.Length == c.Length
和e[i] == c[i]
,則認為該模式相符。建議:以效能標準
MemoryExtensions.SequenceEqual()
來進行定義。 如果遺漏MemoryExtensions
,請回報編譯錯誤。是否應允許匹配
(string)null
?如果是這樣,
(string)null
應該包含""
,因為MemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")
?static bool IsEmpty(ReadOnlySpan<char> span) { return span switch { (string)null => true, // ok? "" => true, // error: unreachable? _ => false, }; }
建議:常數模式
(string)null
應回報為錯誤。常數模式比對是否應包含對
Span<char>
或ReadOnlySpan<char>
表達式值的運行時間類型測試?static bool Is123<T>(Span<T> s) { return s is "123"; // test for Span<char>? } static bool IsABC<T>(Span<T> s) { return s is Span<char> and "ABC"; // ok? } static bool IsEmptyString<T>(T t) where T : ref struct { return t is ""; // test for ReadOnlySpan<char>, Span<char>, string? }
建議:避免對常數模式進行隱式運行時類型測試。 (
IsABC<T>()
範例是允許的,因為類型測試是明確的。未實作這項建議。 上述所有範例都會產生編譯程序錯誤。
子屬性歸屬是否應考慮常量字串模式、列表模式和
Length
屬性模式?static int ToNum(ReadOnlySpan<char> s) { return s switch { { Length: 0 } => 0, "" => 1, // error: unreachable? ['A',..] => 2, "ABC" => 3, // error: unreachable? _ => 4, }; }
建議:使用與當表達式值為
string
時相同的吸收行為。 這是否意味著在常數字串、清單模式和Length
之間沒有子包含關係,除了[..]
可以匹配任何內容?