Partilhar via


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-se length >= 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-se length >= 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

  1. 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.)
  2. Devemos aceitar um padrão geral seguindo .. numa slice_pattern? (resposta [LDM 2021-05-26]: Sim, qualquer padrão é permitido após uma fatia.)
  3. Por esta definição, o padrão [..] testa para expr.Length >= 0. Devemos omitir esse teste, assumindo que Length é sempre não negativo? (resposta [LDM 2021-05-26]: [..] não emitirá uma verificação de comprimento)