Compartilhar via


Padrões de lista

Nota

Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele 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 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 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/3435

Resumo

Permite que você corresponda uma matriz ou uma lista com uma sequência de padrões, por exemplo, array is [1, 2, 3] corresponderá com uma matriz de inteiros de comprimento três com 1, 2, 3 como seus elementos, respectivamente.

Design detalhado

A sintaxe padrão é modificada da seguinte maneira:

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
  ;

Há dois novos padrões:

  • A lista padrão é usada para combinar elementos.
  • Um slice_pattern só é permitido uma vez e somente diretamente em um 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 — que possui um indexador acessível que usa um Index como um argumento ou, como alternativa, um indexador acessível com um único parâmetro int. Se ambos os indexadores estiverem presentes, o primeiro será preferencial.

Um slice_pattern com um subpadrão é compatível com qualquer tipo que seja contável, bem como segmentável, ele tem um indexador acessível que aceita um Range como argumento, ou então um método acessível Slice com dois parâmetros int. Se ambos estiverem presentes, o primeiro será preferencial.

Um slice_pattern sem um subpadrão é compatível com qualquer tipo compatível com um list_pattern.

Esse conjunto de regras é derivado do padrão do indexador de intervalo .

Verificação de subsunção

A verificação de subsunção funciona como padrões posicionais com ITuple - subpadrões correspondentes são alinhados 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

Diferentemente de:

case [_, 1, ..]: // expr.Length is >= 2 && expr[1] is 1
case [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1

A ordem em que a correspondência de subpadrões acontece em runtime não é especificada, e uma correspondência malsucedida pode não tentar abranger todos os subpadrões.

Dado um comprimento específico, é possível que dois subpadrões se refiram ao mesmo elemento, nesse caso, 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) em que 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 em que 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, no runtime, estamos correspondendo ao mesmo elemento no segundo caso.

Se um subpadrão de fatia corresponder a uma lista ou 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].

As seguintes suposições são feitas sobre os membros que estão sendo usados:

  • A propriedade que torna o tipo contável é considerada como sempre retornando um valor não negativo, se e somente se o tipo for indexável. Por exemplo, o padrão { Length: -1 } nunca pode corresponder a uma matriz.
  • O membro que torna o tipo passível de fatiamento é considerado bem comportado, ou seja, o valor retornado nunca é nulo e é uma sublice adequada da lista que contém.

O comportamento de uma operação de correspondência de padrões será indefinido se qualquer uma das suposições acima não se manter.

Abaixamento

Um padrão do formulário 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 esse padrão; ele apenas afeta outros nós, ou seja, o comprimento e o indexador. Por exemplo, um padrão do formulário expr is [1, .. var s, 3] é equivalente ao código a seguir (se compatível por meio de suporte Index explícito 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 de this[Range] ou Slice subjacente com duas exceções: para string e matrizes, string.Substring e RuntimeHelpers.GetSubArray serão usados, respectivamente.

Perguntas não resolvidas

  1. Devemos dar suporte a matrizes multidimensionais? (resposta [LDM 2021-05-26]: sem suporte. Se quisermos fazer uma versão geral focada na matriz MD, gostaríamos de revisitar todas as áreas em que elas estão atualmente em falta, não apenas padrões de lista.)
  2. Devemos aceitar um padrão geral após .. em um slice_pattern? (resposta [LDM 2021-05-26]: sim, qualquer padrão é permitido após uma fatia.)
  3. Com base nessa definição, o padrão [..] testa em relação a expr.Length >= 0. Devemos omitir esse teste, supondo que Length seja sempre não negativo? (resposta [LDM 2021-05-26]: [..] não emitirá uma verificação de extensão)