Correspondência de padrões de Span<char>
em uma cadeia de caracteres constante
Observação
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ela inclui alterações de especificação propostas, juntamente com as informações necessárias durante o design e o desenvolvimento do recurso. Esses artigos são publicados até que as alterações de especificação propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas divergências entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da reunião de design de idioma (LDM).
Você pode saber mais sobre o processo de adoção de speclets de recursos no padrão de linguagem C# no artigo sobre as especificações de .
Problema do especialista: https://github.com/dotnet/csharplang/issues/8640
Resumo
Permitir a correspondência de padrões de Span<char>
e ReadOnlySpan<char>
em uma cadeia de caracteres constante.
Motivação
Para fins de desempenho, o uso de Span<char>
e ReadOnlySpan<char>
é preferido em vez de cadeias de caracteres em muitos cenários. A estrutura adicionou muitas APIs novas para permitir que você use ReadOnlySpan<char>
no lugar de um string
.
Uma operação comum em strings é usar um switch para testar se é um valor específico, e o compilador otimiza esse switch. No entanto, atualmente, não há como fazer o mesmo em um ReadOnlySpan<char>
com eficiência, além de implementar a opção e a otimização manualmente.
Para incentivar a adoção do ReadOnlySpan<char>
, permitimos a correspondência de padrões de um ReadOnlySpan<char>
, em um string
constante, permitindo assim que também seja utilizado em uma troca.
static bool Is123(ReadOnlySpan<char> s)
{
return s is "123";
}
static bool IsABC(Span<char> s)
{
return s switch { "ABC" => true, _ => false };
}
Projeto detalhado
Alteramos a especificação para padrões constantes da seguinte maneira (a adição proposta é mostrada em negrito):
Dado um valor de entrada padrão
e
e um padrão constanteP
com valor convertidov
,
- se e tiver tipo integral ou tipo de enumeração, ou uma forma anulável de um desses, e v tiver tipo integral, o padrão
P
corresponderá ao valor e se o resultado da expressãoe == v
fortrue
; caso contrário- Se e for do tipo
System.Span<char>
ouSystem.ReadOnlySpan<char>
e c for uma cadeia de caracteres constante e c não tiver um valor constante denull
, o padrão será considerado correspondente seSystem.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c))
retornartrue
.- o padrão
P
corresponderá ao valor e seobject.Equals(e, v)
retornartrue
.
Membros conhecidos
System.Span<T>
e System.ReadOnlySpan<T>
são correspondidos por nomes; devem ser ref struct
s e podem ser definidos fora do corlib.
System.MemoryExtensions
é correspondido pelo nome e pode ser definido fora do corlib.
A assinatura de sobrecargas de System.MemoryExtensions.SequenceEqual
deve corresponder:
public static bool SequenceEqual<T>(System.Span<T>, System.ReadOnlySpan<T>)
public static bool SequenceEqual<T>(System.ReadOnlySpan<T>, System.ReadOnlySpan<T>)
A assinatura de System.MemoryExtensions.AsSpan
deve corresponder:
public static System.ReadOnlySpan<char> AsSpan(string)
Métodos com parâmetros opcionais são excluídos da consideração.
Desvantagens
Nenhum
Alternativas
Nenhum
Perguntas não resolvidas
A correspondência deve ser definida independentemente de
MemoryExtensions.SequenceEqual()
etc.?... o padrão é considerado uma correspondência se
e.Length == c.Length
ee[i] == c[i]
forem iguais para todos os caracteres eme
.Recomendação: definir em termos de
MemoryExtensions.SequenceEqual()
para desempenho. SeMemoryExtensions
estiver ausente, relate o erro de compilação.A correspondência com
(string)null
deve ser permitida?Se sim,
(string)null
deve se subordinar a""
, visto queMemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")
?static bool IsEmpty(ReadOnlySpan<char> span) { return span switch { (string)null => true, // ok? "" => true, // error: unreachable? _ => false, }; }
Recomendação: um padrão constante
(string)null
deve ser reportado como um erro.A correspondência constante de padrões deve incluir um teste de tipo de runtime do valor da expressão para
Span<char>
ouReadOnlySpan<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? }
Recomendação: nenhum teste de tipo de runtime implícito para padrão constante. (
IsABC<T>()
exemplo é permitido porque o teste de tipo é explícito.)Esta recomendação não foi implementada. Todos os exemplos anteriores produzem um erro de compilador.
A subordinação deve considerar padrões de cadeia de caracteres constantes, padrões de listas e padrões de propriedade
Length
?static int ToNum(ReadOnlySpan<char> s) { return s switch { { Length: 0 } => 0, "" => 1, // error: unreachable? ['A',..] => 2, "ABC" => 3, // error: unreachable? _ => 4, }; }
Recomendação: mesmo comportamento de subsunção usado quando o valor da expressão é
string
. (Isso significa que não há subordinação entre cadeias de caracteres constantes, padrões de lista eLength
, além de tratar[..]
como correspondentes a qualquer um?)
Reuniões de design
C# feature specifications