Sdílet prostřednictvím


Porovnávání vzorů Span<char> u konstantního řetězce

Poznámka

Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.

Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v příslušných poznámkách ze schůzky o návrhu jazyka (LDM) .

Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .

Problém šampiona: https://github.com/dotnet/csharplang/issues/8640

Shrnutí

Povolte porovnání vzorů Span<char> a ReadOnlySpan<char> na konstantním řetězci.

Motivace

Pro zvýšení výkonu se v mnoha scénářích upřednostňuje používání Span<char> a ReadOnlySpan<char> před řetězcem. Architektura přidala mnoho nových rozhraní API, která umožňují používat ReadOnlySpan<char> místo string.

Běžnou operací s řetězci je použití přepínače k otestování, pokud jde o konkrétní hodnotu, a kompilátor takový přepínač optimalizuje. V současné době ale neexistuje žádný způsob, jak to udělat u ReadOnlySpan<char> efektivně, kromě implementace přepínače a optimalizace ručně.

Abychom podpořili přijetí ReadOnlySpan<char>, umožňujeme přiřazení vzoru ReadOnlySpan<char>ke konstantě string, což rovněž umožňuje jeho použití v přepínači.

static bool Is123(ReadOnlySpan<char> s)
{
    return s is "123";
}

static bool IsABC(Span<char> s)
{
    return s switch { "ABC" => true, _ => false };
}

Podrobný návrh

Změníme specifikaci pro konstantní vzory následujícím způsobem (navržený dodatek je zobrazen tučně):

Při zadání vstupní hodnoty vzoru e a konstantního vzoru P s převedenou hodnotou v,

  • pokud e má celočíselný typ nebo výčtový typ nebo typ s možnou hodnotou null a v má celočíselný typ, Pvzor odpovídá hodnotě e, pokud je výsledek výrazu e == vtrue; jinak
  • Pokud je e typu System.Span<char> nebo System.ReadOnlySpan<char>a c je konstantní řetězec a c nemá konstantní hodnotu null, pak se vzor považuje za odpovídající, pokud System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c)) vrátí true.
  • vzor Podpovídá hodnotě e, pokud object.Equals(e, v) vrátí true.

Známí členové

System.Span<T> a System.ReadOnlySpan<T> odpovídají názvu, musí být ref structs a dají se definovat mimo corlib.

System.MemoryExtensions se shoduje s názvem a dá se definovat mimo corlib.

Podpis přetížení System.MemoryExtensions.SequenceEqual musí odpovídat:

  • public static bool SequenceEqual<T>(System.Span<T>, System.ReadOnlySpan<T>)
  • public static bool SequenceEqual<T>(System.ReadOnlySpan<T>, System.ReadOnlySpan<T>)

Podpis System.MemoryExtensions.AsSpan musí odpovídat:

  • public static System.ReadOnlySpan<char> AsSpan(string)

Metody s volitelnými parametry jsou vyloučeny z úvahy.

Nevýhody

Žádný

Alternativy

Žádný

Nevyřešené otázky

  1. Mělo by být porovnání definováno nezávisle na MemoryExtensions.SequenceEqual() atd.?

    Vzor je považován za odpovídající, pokud e.Length == c.Length a e[i] == c[i] splňují podmínky pro všechny znaky v e.

    Doporučení: Definujte výkon z hlediska MemoryExtensions.SequenceEqual(). Pokud MemoryExtensions chybí, nahlaste chybu kompilace.

  2. Mělo by být povoleno porovnávání s (string)null?

    Pokud ano, mělo by (string)null pohltit "" od MemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")?

    static bool IsEmpty(ReadOnlySpan<char> span)
    {
        return span switch
        {
            (string)null => true, // ok?
            "" => true,           // error: unreachable?
            _ => false,
        };
    }
    

    Doporučení: Konstantní vzor (string)null by měl být nahlášen jako chyba.

  3. Měla by shoda konstantního vzoru obsahovat běhový test typu hodnoty výrazu pro Span<char> nebo 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?
    }
    

    Doporučení: Žádný implicitní test typu modulu runtime pro konstantní vzor. (IsABC<T>() příklad je povolený, protože test typu je explicitní.)

    Toto doporučení nebylo implementováno. Všechny předchozí ukázky vytvářejí chybu kompilátoru.

  4. Měli byste při subsumpci zvážit vzory konstantních řetězců, vzory seznamů a vzor vlastností Length?

    static int ToNum(ReadOnlySpan<char> s)
    {
        return s switch
        {
            { Length: 0 } => 0,
            "" => 1,        // error: unreachable?
            ['A',..] => 2,
            "ABC" => 3,     // error: unreachable?
            _ => 4,
        };
    }
    

    Doporučení: Stejné chování zahrnutí jako při hodnotě výrazu string. Znamená to, že mezi konstantními řetězci, vzory seznamů a Lengthnení žádná subsumpce, kromě případu, kdy je [..] považováno za shodné s jakýmkoli?

Schůzky o designu

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