Mönstermatch Span<char>
på en konstant sträng
Obs
Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.
Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader fångas upp i de relevanta anteckningarna från språkdesignmöten (LDM).
Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.
Champion-fråga: https://github.com/dotnet/csharplang/issues/8640
Sammanfattning
Tillåt mönster som matchar en Span<char>
och en ReadOnlySpan<char>
på en konstant sträng.
Motivation
För prestanda prefereras användning av Span<char>
och ReadOnlySpan<char>
framför strängar i många scenarier. Ramverket har lagt till många nya API:er så att du kan använda ReadOnlySpan<char>
i stället för en string
.
En vanlig åtgärd på strängar är att använda en växel för att testa om det är ett visst värde, och kompilatorn optimerar en sådan växel. Det finns dock för närvarande inget sätt att göra samma sak på ett ReadOnlySpan<char>
effektivt, förutom att implementera växeln och optimeringen manuellt.
För att uppmuntra till införande av ReadOnlySpan<char>
tillåter vi mönster som matchar en ReadOnlySpan<char>
, på en konstant string
, vilket också gör att den kan användas i en växel.
static bool Is123(ReadOnlySpan<char> s)
{
return s is "123";
}
static bool IsABC(Span<char> s)
{
return s switch { "ABC" => true, _ => false };
}
Detaljerad design
Vi ändrar specifikationen för konstanta mönster enligt följande (det föreslagna tillägget visas i fetstil):
Givet ett mönsterindatavärde
e
och ett konstant mönsterP
med konverterat värdev
,
- om e har en integrerad typ eller uppräkningstyp, eller en nullbar form av en av dessa, och v har en integrerad typ, matchar mönstret
P
värdet e om resultatet av uttryckete == v
ärtrue
; annars- Om e är av typen
System.Span<char>
ellerSystem.ReadOnlySpan<char>
och c är en konstant sträng och c inte har ett konstant värde pånull
anses mönstret matcha omSystem.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c))
returnerartrue
.- mönstret
P
matchar värdet e omobject.Equals(e, v)
returnerartrue
.
Välkända medlemmar
System.Span<T>
och System.ReadOnlySpan<T>
matchas med namn, måste vara ref struct
s och kan definieras utanför corlib.
System.MemoryExtensions
matchas med namn och kan definieras utanför corlib.
Signaturen för System.MemoryExtensions.SequenceEqual
-överlagringar måste matcha:
public static bool SequenceEqual<T>(System.Span<T>, System.ReadOnlySpan<T>)
public static bool SequenceEqual<T>(System.ReadOnlySpan<T>, System.ReadOnlySpan<T>)
Signaturen för System.MemoryExtensions.AsSpan
måste matcha:
public static System.ReadOnlySpan<char> AsSpan(string)
Metoder med valfria parametrar undantas från övervägande.
Nackdelar
Ingen
Alternativ
Ingen
Olösta frågor
Ska matchning definieras oberoende av
MemoryExtensions.SequenceEqual()
osv.... mönstret anses vara matchande om
e.Length == c.Length
oche[i] == c[i]
stämmer för alla tecken ie
.Rekommendation: Definiera i termer av
MemoryExtensions.SequenceEqual()
för prestanda. OmMemoryExtensions
saknas, rapportera kompileringsfel.Bör matchning mot
(string)null
tillåtas?I så fall, bör
(string)null
omfatta""
eftersomMemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")
?static bool IsEmpty(ReadOnlySpan<char> span) { return span switch { (string)null => true, // ok? "" => true, // error: unreachable? _ => false, }; }
Rekommendation: Konstant mönster
(string)null
ska rapporteras som ett fel.Ska mönsterjämförelsen för konstanter innehålla ett typtest vid körning av uttrycksvärdet för
Span<char>
ellerReadOnlySpan<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? }
Rekommendation: Inget implicit körningstyptest för konstant mönster. (
IsABC<T>()
exempel tillåts eftersom typtestet är explicit.)Den här rekommendationen implementerades inte. Alla föregående exempel genererar ett kompilatorfel.
Ska subsumtion beakta konstanta strängmönster, listmönster och
Length
egenskapsmönster?static int ToNum(ReadOnlySpan<char> s) { return s switch { { Length: 0 } => 0, "" => 1, // error: unreachable? ['A',..] => 2, "ABC" => 3, // error: unreachable? _ => 4, }; }
Rekommendation: Samma undersumtionsbeteende som används när uttrycksvärdet är
string
. (Innebär det ingen inkludering mellan konstanta strängar, listmönster ochLength
, förutom att[..]
behandlas som ett som matchar vad som helst?)
Designa möten
C# feature specifications