Correspondência de padrão 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. Ele inclui mudanças de especificação propostas, juntamente com as informações necessárias durante o design e desenvolvimento do recurso. Estes artigos são publicados até que as alterações de especificações propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da Language Design Meeting (LDM).
Você pode saber mais sobre o processo de adoção de especificações de recursos no padrão de linguagem C# no artigo sobre as especificações .
Resumo
Permite que o padrão corresponda a um Span<char>
e a um ReadOnlySpan<char>
em uma cadeia de caracteres constante.
Motivação
Para um melhor desempenho, o uso de Span<char>
e ReadOnlySpan<char>
é preferível a strings 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á nenhuma maneira de fazer o mesmo em um ReadOnlySpan<char>
de forma eficiente, além de implementar o switch e a otimização manualmente.
A fim de incentivar a adoção de ReadOnlySpan<char>
permitimos a correspondência de padrões de um ReadOnlySpan<char>
, em uma string
constante, permitindo assim também que ele seja usado em um interruptor.
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 de para padrões constantes da seguinte forma (a adição proposta é evidenciada em negrito):
Dado um valor de entrada padrão
e
e um padrão constanteP
com valor convertidov
,
- se e têm tipo integral ou tipo enum, ou uma forma anulável de um destes, e v tem tipo integral, o padrão
P
combina com o valor e se o resultado da expressãoe == v
étrue
; 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
, então o padrão será considerado correspondente seSystem.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c))
retornartrue
.- O padrão
P
corresponde o valor e seobject.Equals(e, v)
retornartrue
.
Membros bem conhecidos
System.Span<T>
e System.ReadOnlySpan<T>
são correspondidos pelo nome, devem ser ref struct
s e podem ser definidos fora de corlib.
System.MemoryExtensions
é emparelhado pelo nome e pode ser definido fora do corlib.
A assinatura das 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
precisa corresponder a:
public static System.ReadOnlySpan<char> AsSpan(string)
Os métodos com parâmetros opcionais são excluídos da consideração.
Desvantagens
Nenhum
Alternativas
Nenhum
Questões por resolver
A correspondência deve ser definida independentemente de
MemoryExtensions.SequenceEqual()
etc.?... o padrão é considerado igual se
e.Length == c.Length
ee[i] == c[i]
forem idênticos para todos os caracteres eme
.Recomendação: Definir em termos de
MemoryExtensions.SequenceEqual()
para otimizar o desempenho. SeMemoryExtensions
estiver faltando, informe erro de compilação.Deve ser permitida a correspondência com
(string)null
?Em caso afirmativo, deve
(string)null
subsumir""
desdeMemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")
?static bool IsEmpty(ReadOnlySpan<char> span) { return span switch { (string)null => true, // ok? "" => true, // error: unreachable? _ => false, }; }
Recomendação: Padrão constante
(string)null
deve ser relatado como um erro.Deve a correspondência de padrão constante incluir um teste de tipo em tempo de execução para o valor da expressão
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 tempo de execução 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 subsunção deve considerar padrões de cadeia de caracteres constantes, padrões de lista e padrão 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á subsunção entre cadeias de caracteres constantes, padrões de lista eLength
, além de tratar[..]
como correspondendo a qualquer?)
Reuniões de design
C# feature specifications