Match em Rust
O match compara um valor com uma lista de padrões e executa o código do primeiro que se encaixar. Se você já usou um switch em outra linguagem, pense no match como uma versão bem mais poderosa dele. E se nunca usou, tudo bem: é uma das ferramentas mais úteis para aprender logo no começo.
Match básico
Seção intitulada “Match básico”fn main() { let day = 3;
match day { 1 => println!("Segunda-feira"), 2 => println!("Terça-feira"), 3 => println!("Quarta-feira"), 4 => println!("Quinta-feira"), 5 => println!("Sexta-feira"), _ => println!("Fim de semana"), }}Saída:
Quarta-feiraCada linha padrão => código é um braço (arm) do match. O _ é um curinga: ele aceita qualquer valor que não apareceu nos braços acima dele. O match exige que todos os valores possíveis sejam tratados, por isso o _ costuma estar lá para cobrir “todo o resto”.
Vários valores de uma vez
Seção intitulada “Vários valores de uma vez”Você pode juntar vários valores em um único braço usando |:
fn main() { let day = 6;
match day { 1 | 2 | 3 | 4 | 5 => println!("Dia útil"), 6 | 7 => println!("Fim de semana"), _ => println!("Dia inválido"), }}Intervalos
Seção intitulada “Intervalos”Com números, você pode aceitar um intervalo inteiro usando ..=:
fn main() { let score = 85;
match score { 90..=100 => println!("A"), 75..=89 => println!("B"), 60..=74 => println!("C"), _ => println!("F"), }}match como expressão
Seção intitulada “match como expressão”Assim como o if, o match pode produzir um valor:
fn main() { let day = 6;
let kind = match day { 1 | 2 | 3 | 4 | 5 => "dia útil", 6 | 7 => "fim de semana", _ => "desconhecido", };
println!("{kind}");}Fazendo match com texto e caracteres
Seção intitulada “Fazendo match com texto e caracteres”O match não serve só para números. Ele também funciona com string slices (&str) e com caracteres, e intervalos de caracteres como 'a'..='z' funcionam igualzinho aos intervalos de números:
fn main() { let command = "parar"; match command { "iniciar" => println!("Iniciando..."), "parar" | "sair" => println!("Parando."), _ => println!("Comando desconhecido: {command}"), }
let letter = 'k'; let kind = match letter { 'a' | 'e' | 'i' | 'o' | 'u' => "uma vogal", 'a'..='z' => "uma consoante", '0'..='9' => "um dígito", _ => "outra coisa", }; println!("'{letter}' é {kind}");
let name = String::from("Ferris"); match name.as_str() { "Ferris" => println!("Oi, caranguejo!"), _ => println!("Oi, {name}!"), }}Saída:
Parando.'k' é uma consoanteOi, caranguejo!Duas coisas merecem atenção aqui:
- A ordem importa. O
'a'também está dentro de'a'..='z', mas o braço das vogais vem primeiro, então as vogais nunca chegam ao braço das consoantes. O Rust sempre escolhe o primeiro braço que se encaixa. - Uma
Stringprecisa de.as_str(). Um texto escrito entre aspas, como"Ferris", é um&str. Se você fizermatchde umaStringdiretamente contra ele, o Rust para comerror[E0308]: mismatched types ... expected String, found &str(os tipos não batem: ele esperavaStringe encontrou&str). Chamar.as_str()dá a você uma visão&strdaString, que os padrões conseguem comparar. (Veja a página de Strings para entender a diferença entre os dois.)
O match diferencia maiúsculas de minúsculas: "Parar" não combinaria com "parar". Se o texto vier de um usuário, um truque comum é fazer o match com input.to_lowercase().as_str().
match ou if/else?
Seção intitulada “match ou if/else?”Para uma verificação simples de verdadeiro/falso, os dois funcionam. Mas o match começa a ganhar quando você tem mais de duas ou três possibilidades: ele fica mais fácil de ler do que uma longa cadeia de else if, e o compilador confere se você cobriu todos os casos. Para uma única condição de sim ou não, o if/else continua sendo a ferramenta certa.
Prática
Seção intitulada “Prática”1. Dias do mês
Seção intitulada “1. Dias do mês”Guarde o número de um mês month (2). Use o match como expressão para descobrir quantos dias ele tem (ignore os anos bissextos) e depois imprima O mês 2 tem 28 dias. Dica: os meses 1, 3, 5, 7, 8, 10 e 12 têm 31 dias; junte todos em um único braço com |.
Ver solução
fn main() { let month = 2;
let days = match month { 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, 4 | 6 | 9 | 11 => 30, 2 => 28, _ => 0, // não é um mês de verdade };
println!("O mês {month} tem {days} dias");}Saída:
O mês 2 tem 28 dias2. Códigos de status HTTP
Seção intitulada “2. Códigos de status HTTP”Servidores web respondem com um número. Transforme um código code em um significado curto: 200 é "OK", 404 é "Not Found", qualquer outro de 400 a 499 é "Erro do cliente", de 500 a 599 é "Erro do servidor", e qualquer outra coisa é "Desconhecido". Teste com 503. Dica: coloque o braço exato do 404 acima do intervalo 400..=499, senão ele nunca vai ser alcançado.
Ver solução
fn main() { let code = 503;
let meaning = match code { 200 => "OK", 404 => "Not Found", // precisa vir antes do intervalo 400..=499 400..=499 => "Erro do cliente", 500..=599 => "Erro do servidor", _ => "Desconhecido", };
println!("{code}: {meaning}");}Saída:
503: Erro do servidor- O
matchcompara um valor com padrões e executa o braço que combinar. - Todo valor possível precisa ser tratado: use
_como curinga. - Junte valores com
|ou aceite um intervalo com..=. - Você também pode fazer match com texto
&stre com valoreschar; use.as_str()para fazer match com umaString. - Assim como o
if, omatchpode ser usado como expressão para produzir um valor.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. O que o padrão _ faz em uma expressão match?
2. O que acontece se um match não tratar todos os valores possíveis e não tiver um braço _?
3. Como aceitar vários valores em um único braço, como 1, 2 ou 3?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- The match Control Flow Construct — The Rust Book (em inglês): o capítulo oficial, que também mostra o
matchcom enums eOption. - match — Rust by Example (em inglês): um exemplo compacto que você pode rodar, com valores,
|, intervalos e_. - Range patterns — The Rust Reference (em inglês): exatamente quais tipos e formas de intervalo você pode usar em um padrão.
- Match expressions — The Rust Reference (em inglês): as regras precisas dos braços, dos guards e de como um
matchproduz o seu valor.