Patterns & Matching (3.0)
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 87 de 110.
O Dart 3 introduziu o pattern matching, uma maneira poderosa de desestruturar e inspecionar dados em uma única expressão. Patterns permitem extrair valores de objetos, verificar sua estrutura e vincular variáveis - tudo de uma vez.
Você já viu a desestruturação básica com records. Patterns estendem isso para funcionar com objetos, listas e mapas:
void main() {
// Patterns de lista
var numbers = [1, 2, 3];
var [a, b, c] = numbers;
print('$a, $b, $c'); // 1, 2, 3
// Patterns de mapa
var user = {'name': 'Alice', 'age': 30};
var {'name': name, 'age': age} = user;
print('$name is $age'); // Alice is 30
}Padrões tornam-se especialmente poderosos em expressões switch. Você pode fazer a correspondência de tipo, valor e estrutura simultaneamente:
String describe(Object obj) {
return switch (obj) {
int n when n < 0 => 'Negative number',
int n => 'Positive number: $n',
String s => 'String of length ${s.length}',
[int first, ...] => 'List starting with $first',
_ => 'Something else',
};
}
void main() {
print(describe(-5)); // Número negativo
print(describe(42)); // Número positivo: 42
print(describe([1, 2, 3])); // Lista começando com 1
}A cláusula when adiciona condições aos padrões, e ... corresponde aos elementos restantes em uma lista. O underscore _ atua como um curinga que corresponde a qualquer coisa. Combinados com classes seladas, os padrões permitem uma manipulação exaustiva e segura quanto ao tipo de estruturas de dados complexas.
Desafio
FácilVamos construir um classificador de dados que utiliza correspondência de padrões (pattern matching) para analisar e categorizar diferentes tipos de entrada! Você criará um sistema que pode identificar e descrever várias estruturas de dados usando os poderosos recursos de pattern matching do Dart 3.
Você organizará seu código em dois arquivos:
classifier.dart: Crie uma função chamadaclassifyque recebe um parâmetroObjecte retorna umaStringde descrição. Use uma expressão switch com pattern matching para lidar com estes casos:- Uma lista vazia
[]deve retornarEmpty list - Uma lista com exatamente um elemento inteiro deve retornar
Single item: [value] - Uma lista com exatamente dois elementos deve retornar
Pair: [first] and [second] - Uma lista começando com um inteiro seguido por mais elementos deve retornar
List starting with [first], length: [total length](use o padrão rest...) - Um mapa contendo as chaves
'name'e'age'deve retornar[name] is [age] years old(use a desestruturação de padrão de mapa) - Um número inteiro que seja negativo (use a cláusula
when) deve retornarNegative: [value] - Um número inteiro que seja zero deve retornar
Zero - Qualquer outro número inteiro deve retornar
Positive: [value] - Qualquer outro valor deve retornar
Unknown type
- Uma lista vazia
main.dart: Importe seu classificador e demonstre o pattern matching com várias entradas. Imprima o resultado da classificação de cada um destes valores:- Uma lista vazia
[] - Uma lista com um elemento:
[42] - Uma lista com dois elementos:
['hello', 'world'] - Uma lista mais longa:
[1, 2, 3, 4, 5] - Um mapa:
{'name': 'Alice', 'age': 25} - O número inteiro
-10 - O número inteiro
0 - O número inteiro
99
- Uma lista vazia
Este desafio combina padrões de lista, padrões de mapa, a cláusula when para guardas e o padrão rest (...) - todos os principais recursos de pattern matching da lição!
Saída esperada:
Empty list
Single item: 42
Pair: hello and world
List starting with 1, length: 5
Alice is 25 years old
Negative: -10
Zero
Positive: 99Folha de consulta
O Dart 3 introduziu o pattern matching para desestruturação e inspeção de dados em uma única expressão.
Padrões de Lista
Extraia valores de listas:
var numbers = [1, 2, 3];
var [a, b, c] = numbers;
print('$a, $b, $c'); // 1, 2, 3Padrões de Mapa
Desestruture mapas por chave:
var user = {'name': 'Alice', 'age': 30};
var {'name': name, 'age': age} = user;
print('$name is $age'); // Alice is 30Expressões Switch com Padrões
Corresponda por tipo, valor e estrutura:
String describe(Object obj) {
return switch (obj) {
int n when n < 0 => 'Negative number',
int n => 'Positive number: $n',
String s => 'String of length ${s.length}',
[int first, ...] => 'List starting with $first',
_ => 'Something else',
};
}Recursos de Padrões
- Cláusula
when: Adiciona condições aos padrões ...(padrão rest): Corresponde aos elementos restantes em uma lista_(wildcard): Corresponde a qualquer coisa
Experimente você mesmo
import 'classifier.dart';
void main() {
// TODO: Use a função classify para categorizar cada valor
// e imprimir os resultados
// Teste com uma lista vazia
print(classify([]));
// TODO: Teste com uma lista contendo um elemento: [42]
// TODO: Teste com uma lista contendo dois elementos: ['hello', 'world']
// TODO: Teste com uma lista mais longa: [1, 2, 3, 4, 5]
// TODO: Teste com um map: {'name': 'Alice', 'age': 25}
// TODO: Teste com o inteiro -10
// TODO: Teste com o inteiro 0
// TODO: Teste com o inteiro 99
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosBibliotecas e ImportaçõesIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosVariáveis de InstânciaFundamentos de ConstrutoresRecapitulação - Calculadora Simples4Null Safety
Introdução ao Null SafetyNullable vs Non-NullableOs Operadores ? e !Palavra-chave Late e Null SafetyOperadores Null-AwareNull Safety em ClassesRecapitulação - Sistema de Perfil de Usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementando vs EstendendoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Generics
Visão Geral de List, Set e MapColeções Type-SafeClasses GenéricasMétodos GenéricosRestrições de GenericsIterable e IteratorRecapitulação - Armazenamento Genérico13Conceitos Avançados de POO
Composição vs HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário2Construtores em Dart
Construtor PadrãoConstrutores NomeadosListas de InicializaçãoConstrutores ConstantesConstrutores FactoryConstrutores de RedirecionamentoRecapitulação - Shape Builder5Encapsulamento
Membros Públicos vs PrivadosA Convenção do Prefixo _Privacidade em Nível de BibliotecaAprofundamento em Getters & SettersOcultação de InformaçãoRecapitulação - Registros de Estudantes8Mixins
Introdução aos MixinsCriando MixinsUsando Múltiplos MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema Animal11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode & ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs EstáticosCampos Final & ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Conta Bancária6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodoA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do PolimorfismoPolimorfismo via InterfacesVerificação de Tipos em Tempo de ExecuçãoOs Operadores is & asPalavra-chave CovariantRecapitulação - Processador de Pagamentos12POO Assíncrona
Futures e async/awaitFundamentos de StreamsStream ControllersConstrutores AssíncronosAsync em Métodos de ClasseRecapitulação - Data Fetcher15Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository