Partager via


Correspondance de modèle d’une Span<char> sur une chaîne constante

Remarque

Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Il inclut les modifications de spécification proposées, ainsi que les informations nécessaires pendant la conception et le développement de la fonctionnalité. Ces articles sont publiés jusqu’à ce que les modifications de spécification proposées soient finalisées et incorporées dans la spécification ECMA actuelle.

Il peut y avoir des différences entre la spécification de la fonctionnalité et l’implémentation terminée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).

Vous pouvez en savoir plus sur le processus d’adoption des speclets de fonctionnalités dans la norme de langage C# dans l’article sur les spécifications .

Résumé

Permettre la correspondance de modèle d’une Span<char> et d’une ReadOnlySpan<char> dans une chaîne constante.

Motivation

Pour la performance, l’utilisation de Span<char> et de ReadOnlySpan<char> est préférée à la chaîne de caractères dans de nombreux scénarios. Le framework a ajouté de nombreuses nouvelles API pour vous permettre d’utiliser ReadOnlySpan<char> à la place d’un string.

Une opération courante sur les chaînes consiste à utiliser un commutateur pour tester s’il s’agit d’une valeur particulière, et le compilateur optimise ce commutateur. Toutefois, il n’existe actuellement aucun moyen de procéder de la même façon sur un ReadOnlySpan<char> efficacement, à part l’implémentation du commutateur et de l’optimisation manuellement.

Afin d’encourager l’adoption de ReadOnlySpan<char>, nous permettons la correspondance de modèle d’une ReadOnlySpan<char> sur une constante string, ce qui permet également son utilisation dans une instruction switch.

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

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

Conception détaillée

Nous modifions la spécification pour les modèles constants comme suit (l’ajout proposé est présenté en gras) :

Étant donné une valeur d’entrée de modèle e et un modèle constant P avec une valeur convertie v,

  • si e possède un type intégral ou un type d’énumération, ou une forme autorisant une valeur nulle de l’un de ces types et v possède un type intégral, le modèle Pcorrespond à la valeur e si le résultat de l’expression e == v est true; autrement
  • Si e est de type System.Span<char> ou System.ReadOnlySpan<char>, et c est une chaîne constante, et c n’a pas de valeur constante de null, le modèle est considéré comme correspondant si System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c)) retourne true.
  • le modèle Pcorrespond à la valeur e si object.Equals(e, v) retourne true.

Membres connus

System.Span<T> et System.ReadOnlySpan<T> sont mis en correspondance par nom, doivent être ref structs et peuvent être définis en dehors du corlib.

System.MemoryExtensions est associé par nom et peut être défini en dehors de corlib.

La signature des surcharges de System.MemoryExtensions.SequenceEqual doit correspondre à :

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

La signature de System.MemoryExtensions.AsSpan doit correspondre à :

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

Les méthodes avec des paramètres facultatifs sont exclues de la considération.

Inconvénients

Aucun

Alternatives

Aucun

Questions non résolues

  1. La correspondance doit-elle être définie indépendamment de MemoryExtensions.SequenceEqual() etc. ?

    ... le modèle est considéré comme correspondant si e.Length == c.Length et e[i] == c[i] pour tous les caractères de e.

    Recommandation : Définir en termes de MemoryExtensions.SequenceEqual() pour les performances. Si MemoryExtensions est manquant, signalez l’erreur de compilation.

  2. La mise en correspondance par rapport à (string)null doit-elle être autorisée ?

    Si c’est le cas, (string)null devrait-il englober "" étant donné MemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("") ?

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

    Recommandation : le modèle constant (string)null doit être signalé comme une erreur.

  3. La correspondance du modèle constant doit-elle inclure un test de type runtime de la valeur d’expression pour Span<char> ou 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?
    }
    

    Recommandation : aucun test de type d’exécution implicite pour le modèle constant. (L'exempleIsABC<T>() est autorisé, car le test de type est explicite.)

    Cette recommandation n’a pas été mise en œuvre. Tous les exemples précédents produisent une erreur du compilateur.

  4. La subsomption doit-elle prendre en compte les modèles de chaînes constantes, les modèles de liste et le modèle de propriété Length ?

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

    Recommandation : même comportement de soussomption que celui utilisé lorsque la valeur de l'expression est string. (Cela signifie-t-il qu'il n'y a pas de subsomption entre les chaînes constantes, les modèles de liste et Length, à l'exception de traiter [..] comme une correspondance à n'importe quoi ?)

Concevoir des réunions

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