Delen via


Patroonovereenkomst Span<char> op een constante tekenreeks

Notitie

Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.

Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. Deze verschillen worden vastgelegd in de relevante LDM (Language Design Meeting) notities.

Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.

Kampioenprobleem: https://github.com/dotnet/csharplang/issues/8640

Samenvatting

Sta patroonmatching toe van een Span<char> en een ReadOnlySpan<char> op een constante string.

Motivatie

Voor performance heeft het gebruik van Span<char> en ReadOnlySpan<char> de voorkeur boven strings in veel scenario's. Het framework heeft veel nieuwe API's toegevoegd waarmee u ReadOnlySpan<char> kunt gebruiken in plaats van een string.

Een veelvoorkomende bewerking voor tekenreeksen is het gebruik van een switch-instructie om te testen of het een bepaalde waarde is, waarbij de compiler zo'n switch optimaliseert. Er is momenteel echter geen manier om hetzelfde te doen op een ReadOnlySpan<char> efficiënt, behalve het handmatig implementeren van de switch en de optimalisatie.

Om de acceptatie van ReadOnlySpan<char> te bevorderen, staan we toe dat een patroon dat overeenkomt met een ReadOnlySpan<char>, op een constante stringwordt gebruikt, zodat het ook in een switch kan worden toegepast.

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

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

Gedetailleerd ontwerp

We wijzigen de specificatie voor constante patronen als volgt (de voorgestelde toevoeging wordt vet weergegeven):

Gezien een patrooninvoerwaarde e en een constant patroon P met geconverteerde waarde v,

  • als e integraal type of opsommingstype heeft, of een null-vorm van een van deze, en v integraal type heeft, komt het patroon Povereen met de waarde e als het resultaat van de expressie e == vtrueis; anders
  • Als e van het type System.Span<char> of System.ReadOnlySpan<char>is en c een constante tekenreeks is en c- geen constante waarde van nullheeft, wordt het patroon beschouwd als overeenkomend als System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c))trueretourneert.
  • Het patroon Pkomt overeen met de waarde e wanneer object.Equals(e, v)trueretourneert.

Bekende leden

System.Span<T> en System.ReadOnlySpan<T> overeenkomen met de naam, moeten ref structzijn en kunnen buiten corlib worden gedefinieerd.

System.MemoryExtensions wordt op naam vergeleken en kan buiten corlib worden gedefinieerd.

De signatuur van System.MemoryExtensions.SequenceEqual overloads moet overeenkomen:

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

De handtekening van System.MemoryExtensions.AsSpan moet overeenkomen met:

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

Methoden met optionele parameters worden uitgesloten van overweging.

Nadelen

Geen

Alternatieven

Geen

Niet-opgeloste vragen

  1. Moeten overeenkomsten onafhankelijk van MemoryExtensions.SequenceEqual() enzovoort worden gedefinieerd?

    ... het patroon wordt beschouwd als overeenkomend als e.Length == c.Length en e[i] == c[i] voor alle tekens in e.

    Aanbeveling: definieer in termen van MemoryExtensions.SequenceEqual() voor de prestaties. Als MemoryExtensions ontbreekt, rapporteert u een compilatiefout.

  2. Moet matchen tegen (string)null toegestaan worden?

    Als dat het geval is, moet (string)null"" insluiten sinds MemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")?

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

    Aanbeveling: Het constantenpatroon (string)null moet als een fout worden gerapporteerd.

  3. Moet de constante patroonmatching een runtime-typetest bevatten van de expressiewaarde voor Span<char> of 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?
    }
    

    Aanbeveling: Geen impliciete runtimetypetest voor constant patroon. (IsABC<T>() voorbeeld is toegestaan omdat de typetest expliciet is.)

    Deze aanbeveling is niet geïmplementeerd. Alle voorgaande voorbeelden produceren een compilerfout.

  4. Moet subsumptie rekening houden met constante tekenreekspatronen, lijstpatronen en Length-eigenschapspatronen?

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

    Aanbeveling: Hetzelfde subsumeringsgedrag dat wordt gebruikt wanneer de expressiewaarde stringis. (Betekent dit geen subsamenvatting tussen constante tekenreeksen, lijstpatronen en Length, behalve het behandelen van [..] als overeenkomende waarden?)

Ontwerpvergaderingen

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