共用方式為


常數位串上的模式比對 Span<char>

注意

本文是功能規格。 規格可作為功能的設計檔。 其中包含建議的規格變更,以及功能設計和開發期間所需的資訊。 這些文章會發佈,直到提議的規格變更完成並併併入目前的ECMA規格為止。

功能規格與已完成實作之間可能有一些差異。 這些差異在相關的 語言設計會議記錄(LDM)中擷取。

您可以在 規格一文中深入瞭解將功能規範採納至 C# 語言標準的過程

總結

允許在常數字符串上進行 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 structs,而且可以在 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)

選擇性參數的方法會從考慮中排除。

缺點

沒有

替代方案

沒有

未解決的問題

  1. 比對是否應該獨立於 MemoryExtensions.SequenceEqual() 等進行定義?

    如果 e中所有字元都具有 e.Length == c.Lengthe[i] == c[i],則認為該模式相符。

    建議:以效能標準 MemoryExtensions.SequenceEqual() 來進行定義。 如果遺漏 MemoryExtensions,請回報編譯錯誤。

  2. 是否應允許匹配 (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 應回報為錯誤。

  3. 常數模式比對是否應包含對 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>() 範例是允許的,因為類型測試是明確的。

    未實作這項建議。 上述所有範例都會產生編譯程序錯誤。

  4. 子屬性歸屬是否應考慮常量字串模式、列表模式和 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之間沒有子包含關係,除了 [..] 可以匹配任何內容?

設計會議

https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-07.md#readonlyspanchar-patterns