Pular para o conteúdo

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.

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-feira
▶ Experimente você mesmo

Cada 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”.

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"),
}
}
▶ Experimente você mesmo

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"),
}
}
▶ Experimente você mesmo

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}");
}
▶ Experimente você mesmo

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 consoante
Oi, caranguejo!
▶ Experimente você mesmo

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 String precisa de .as_str(). Um texto escrito entre aspas, como "Ferris", é um &str. Se você fizer match de uma String diretamente contra ele, o Rust para com error[E0308]: mismatched types ... expected String, found &str (os tipos não batem: ele esperava String e encontrou &str). Chamar .as_str() dá a você uma visão &str da String, 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().

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.

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 dias
▶ Experimente você mesmo

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
▶ Experimente você mesmo
  • O match compara 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 &str e com valores char; use .as_str() para fazer match com uma String.
  • Assim como o if, o match pode ser usado como expressão para produzir um valor.

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