Padrões de lista
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 reunião de design de linguagem (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 .
Questão campeã: https://github.com/dotnet/csharplang/issues/3435
Resumo
Permite que você corresponda a uma matriz ou uma lista com uma sequência de padrões, por exemplo, array is [1, 2, 3]
corresponderá a uma matriz inteira do comprimento três com 1, 2, 3 como seus elementos, respectivamente.
Projeto detalhado
A sintaxe do padrão é modificada da seguinte forma:
list_pattern_clause
: '[' (pattern (',' pattern)* ','?)? ']'
;
list_pattern
: list_pattern_clause simple_designation?
;
slice_pattern
: '..' pattern?
;
primary_pattern
: list_pattern
| slice_pattern
| // all of the pattern forms previously defined
;
Existem dois novos padrões:
- O list_pattern é usado para corresponder elementos.
- Uma slice_pattern só é permitida uma vez e apenas diretamente numa list_pattern_clause e descarta zero ou mais elementos.
Compatibilidade de padrões
Um list_pattern é compatível com qualquer tipo que seja contável, bem como indexável — ele tem um indexador acessível que toma um Index
como argumento ou, alternativamente, um indexador acessível com um único parâmetro int
. Se ambos os indexadores estiverem presentes, o primeiro é preferido.
Um slice_pattern com um subpadrão é compatível com qualquer tipo que seja contável, bem como fatiável — possui um indexador acessível que aceita um Range
como argumento ou, alternativamente, um método Slice
acessível com dois parâmetros int
. Se ambos estiverem presentes, o primeiro é preferível.
Um slice_pattern sem um subpadrão é compatível com qualquer tipo que seja compatível com um list_pattern.
Este conjunto de regras é derivado do padrão de indexador do intervalo .
Verificação da subsunção
A verificação de subsunção funciona como padrões posicionais com ITuple
- os subpadrões correspondentes são correspondidos por posição mais um nó adicional para testar o comprimento.
Por exemplo, o código a seguir produz um erro porque ambos os padrões produzem o mesmo DAG:
case [_, .., 1]: // expr.Length is >= 2 && expr[^1] is 1
case [.., _, 1]: // expr.Length is >= 2 && expr[^1] is 1
Ao contrário:
case [_, 1, ..]: // expr.Length is >= 2 && expr[1] is 1
case [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1
A ordem na qual os subpadrões são correspondidos em tempo de execução não é especificada, e uma tentativa de correspondência falhada pode não tentar corresponder a todos os subpadrões.
Dado um comprimento específico, é possível que dois subpadrões se refiram ao mesmo elemento, caso em que um teste para esse valor é inserido no DAG de decisão.
- Por exemplo,
[_, >0, ..] or [.., <=0, _]
torna-selength >= 2 && ([1] > 0 || length == 3 || [^2] <= 0)
onde o valor de comprimento de 3 implica o outro teste. - Por outro lado,
[_, >0, ..] and [.., <=0, _]
torna-selength >= 2 && [1] > 0 && length != 3 && [^2] <= 0
onde o valor de comprimento de 3 não permite o outro teste.
Como resultado, um erro é produzido para algo como case [.., p]: case [p]:
porque, em tempo de execução, estamos combinando o mesmo elemento no segundo caso.
Se um subpadrão de fatia corresponder a uma lista ou a um valor de comprimento, os subpadrões serão tratados como se fossem um subpadrão direto da lista que contém. Por exemplo, [..[1, 2, 3]]
subsume um padrão da forma [1, 2, 3]
.
Os seguintes pressupostos são feitos sobre os membros que estão sendo usados:
- Presume-se que a propriedade que torna o tipo contável sempre retorna um valor não negativo, se e somente se o tipo é indexável. Por exemplo, o padrão
{ Length: -1 }
nunca pode corresponder a uma matriz. - O membro que torna o tipo seccionável presume-se que é bem comportado, isto é, o valor de retorno nunca é nulo, sendo uma sublista adequada da lista que contém.
O comportamento de uma operação de correspondência de padrões é indefinido se qualquer uma das suposições acima não se sustentar.
Rebaixamento
Um padrão da forma expr is [1, 2, 3]
é equivalente ao seguinte código:
expr.Length is 3
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Index(1, fromEnd: false)] is 2
&& expr[new Index(2, fromEnd: false)] is 3
Um slice_pattern age como um descarte adequado; ou seja, nenhum teste será emitido para tal padrão, mas, em vez disso, apenas afeta outros nós, isto é, o comprimento e o indexador. Por exemplo, um padrão da forma expr is [1, .. var s, 3]
é equivalente ao seguinte código (se compatível com os suportes explícitos Index
e Range
):
expr.Length is >= 2
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))] is var s
&& expr[new Index(1, fromEnd: true)] is 3
O tipo de entrada para o slice_pattern é o tipo de retorno do método this[Range]
ou Slice
subjacente, com duas exceções: Para string
e matrizes, string.Substring
e RuntimeHelpers.GetSubArray
serão usados, respectivamente.
Questões por resolver
- Devemos suportar matrizes multidimensionais? (resposta [LDM 2021-05-26]: Não suportado. Se quisermos fazer uma versão geral focada no MD-array, gostaríamos de revisitar todas as áreas que faltam no momento, não apenas padrões de lista.)
- Devemos aceitar um padrão geral seguindo
..
numa slice_pattern? (resposta [LDM 2021-05-26]: Sim, qualquer padrão é permitido após uma fatia.) - Por esta definição, o padrão
[..]
testa paraexpr.Length >= 0
. Devemos omitir esse teste, assumindo queLength
é sempre não negativo? (resposta [LDM 2021-05-26]:[..]
não emitirá uma verificação de comprimento)
C# feature specifications