Rust: Correspondência avançada de padrões em Rust

Última atualização: 2026-08-26

A correspondência de padrões é um dos recursos mais poderosos da linguagem Rust, e técnicas avançadas como guardas match, ligações @ e padrões múltiplos permitem que você exerça um controle mais refinado sobre suas correspondências — não apenas “correspondência de valores”, mas “correspondência de condições”.

Se a correspondência básica de padrões é como uma questão de múltipla escolha (escolher um ramo para executar), então a correspondência avançada de padrões é como uma questão composta — você pode verificar valores, vincular referências e avaliar condições adicionais, tudo ao mesmo tempo.


1. O que você vai aprender


2. Uma história sobre a avaliação de desempenho de um funcionário

(1) O desafio: usar uma cadeia de instruções if-else para uma classificação abrangente

Tom é o gerente de RH da empresa e precisa atribuir avaliações abrangentes com base nas pontuações de desempenho e nos registros de assiduidade dos funcionários.

As regras são as seguintes:

Nível Pontuação de desempenho Requisitos de frequência
A+ ≥95 Assiduidade perfeita (≥22 dias)
A ≥85 Frequência ≥ 20 dias
B ≥70 Frequência ≥ 18 dias
C ≥60
D <60

No início, ele escreveu uma longa sequência de if-else:

RUST
fn rate_employee(score: u32, attendance: u32) -> &'static str {
    if score >= 95 && attendance >= 22 {
        "A+"
    } else if score >= 85 && attendance >= 20 {
        "A"
    } else if score >= 70 && attendance >= 18 {
        "B"
    } else if score >= 60 {
        "C"
    } else {
        "D"
    }
}

Embora esse código funcione, ele apresenta vários problemas: as condições estão espalhadas por uma sequência de instruções if-else, o que dificulta a leitura, e não há uma verificação exaustiva — se regras de classificação forem adicionadas no futuro, seria fácil deixá-las passar despercebidas. Além disso, a relação entre as notas e a frequência não está clara o suficiente.

(2) Abordagens avançadas para correspondência de padrões em Rust

RUST
fn rate_employee(score: u32, attendance: u32) -> &'static str {
    match score {
        // Guard Requirements: Meeting the Score Requirement + Attendance Requirements Met
        s if s >= 95 && attendance >= 22 => "A+",
        s if s >= 85 && attendance >= 20 => "A",
        s if s >= 70 && attendance >= 18 => "B",
        s if s >= 60 => "C",
        _ => "D",  // Fallback: score < 60
    }
}

fn main() {
    let employees = [
        ("Alice", 98, 23),
        ("Bob", 88, 21),
        ("Charlie", 88, 17),  // High scores but insufficient attendance
        ("Diana", 72, 19),
        ("Eve", 55, 20),
    ];

    for (name, score, attendance) in &employees {
        let rating = rate_employee(*score, *attendance);
        println!("{:8} | Score: {:2} | Attendance: {:2} days | Rating: {}",
            name, score, attendance, rating);
    }
}

Resultado:

TEXT 📖 Somente leitura
Alice    | Score: 98 | Attendance: 23 days | Rating: A+
Bob      | Score: 88 | Attendance: 21 days | Rating: A
Charlie  | Score: 88 | Attendance: 17 days | Rating: B
Diana    | Score: 72 | Attendance: 19 days | Rating: B
Eve      | Score: 55 | Attendance: 20 days | Rating: D

match A condição de guarda deixa claras imediatamente as condições para cada ramificação: a relação “E” entre nota e frequência fica claramente visível. _ A ramificação genérica garante a exaustividade. Além disso, a semântica de s if s >= ... para diferentes faixas de notas é mais intuitiva do que a de else if.


3. Visão geral da correspondência avançada de padrões

(1) Mapa conceitual

100%
graph TB
    A[Advanced Pattern Matching] --> B[match Guard]
    A --> C[@ Bind]
    A --> D[Multimode |]
    A --> E[Range Matching]
    A --> F[matches! Macro]
    A --> G[Deconstruction Patterns]
    B --> B1["match x { n if n > 10 => ... }"]
    C --> C1["match x { e @ 1..=5 => ... }"]
    D --> D1["match x { 1 | 3 | 5 => ... }"]
    E --> E1["match x { 1..=10 => ... }"]
    F --> F1["if matches!(x, 1..=5) { ... }"]
    G --> G1["let Point { x, y } = p;"]
    G --> G2["match opt { Some(v @ 1..=10) => ... }"]

(2) Comparação entre métodos de correspondência

Método Sintaxe Quando usar Exemplo
Correspondência básica match x { PAT => .. } Correspondência simples de valor match x { 1 => "one" }
guarda de correspondência match x { PAT if COND => .. } Correspondência + condições adicionais n if n > 10 && n % 2 == 0
@ Vinculação e @ PAT => .. Valor de vinculação quando houver correspondência e @ 1..=10 => e
Multimodo | PAT1 | PAT2 => .. Vários modos compartilham o mesmo ramal 1 | 3 | 5 => "odd"
Intervalo ..= PAT1..=PAT2 => .. Corresponde a um intervalo de valores 1..=5 => "small"
macro de correspondências! matches!(x, PAT) Apenas resultado booleano if matches!(x, 1..=5)
Desconstrução let PAT = value Decomposição de tipos compostos let (a, b) = pair

(3) Referência rápida aos tipos de padrões

Tipo de padrão Sintaxe Alvo da correspondência Exemplo
Literal 1 / "hello" Valor exato match x { 1 => ... }
Atribuição de variável x Qualquer valor, atribuído a x match x { n => ... }
Caractere curinga _ Qualquer valor, ignorado match x { _ => ... }
Multimodo 1 | 2 | 3 Vários valores match x { 1 | 2 => ... }
Intervalo 1..=5 Intervalo fechado match x { 1..=5 => ... }
Desconstruindo tuplas (a, b) Tuplas match pair { (x, y) => ... }
Desconstruindo Estruturas Point { x, y } Estruturas match p { Point { x, y } => ... }
Desconstruindo enumerações Some(v) Variantes de enumeração match opt { Some(v) => ... }
@ Atribuição e @ 1..=10 Intervalo + Atribuição match x { e @ 1..=10 => ... }
Guarda x if x > 0 Modo + Condições match x { n if n > 0 => ... }
Ignorar o restante .. Ignorar alguns campos match p { Point { x, .. } => ... }

4. Exemplos de correspondência avançada

▶ Exemplo 1: Match Guard + @ Binding + Multi-Mode (Dificuldade ⭐⭐)

RUST
// ============================================
// Comprehensive Example: Employee Performance Rating System
// Display match Guard, @ Bind, Multi-pattern
// ============================================

#[derive(Debug)]
enum Department {
    Engineering,
    Sales,
    HR,
    Management,
}

#[derive(Debug)]
struct Employee {
    name: String,
    score: u32,
    attendance: u32,
    department: Department,
}

impl Employee {
    /// Rate employee using advanced pattern matching.
    /// Returns (rating, bonus_percentage).
    fn rate(&self) -> (&'static str, u32) {
        match (self.score, self.attendance) {
            // @ binding: capture the matched score value
            s @ 95..=100 if self.attendance >= 22 => {
                println!("  [@ binding] score {} captured for A+ rating", s);
                ("A+", 30)
            }
            s @ 85..=94 if self.attendance >= 20 => {
                println!("  [@ binding] score {} captured for A rating", s);
                ("A", 20)
            }
            s @ 70..=84 if self.attendance >= 18 => {
                println!("  [@ binding] score {} captured for B rating", s);
                ("B", 10)
            }
            // Multi-pattern: 60..=69 OR exactly 70 with low attendance
            60..=69 | 70..=84 => {
                ("C", 5)  // No @ binding needed here
            }
            // match guard with combined conditions
            s if s < 60 => {
                println!("  [guard] score {} is below 60, rating D", s);
                ("D", 0)
            }
            // Catch-all: should not reach normally
            _ => {
                println!("  [wildcard] unexpected combination");
                ("Unknown", 0)
            }
        }
    }

    /// Check if this employee qualifies for special bonus
    /// using matches! macro.
    fn has_special_bonus(&self) -> bool {
        // matches! returns true if the pattern matches
        matches!(self.department, Department::Engineering | Department::Management)
            && self.score >= 90
    }
}

fn main() {
    let employees = vec![
        Employee {
            name: String::from("Alice"),
            score: 97,
            attendance: 23,
            department: Department::Engineering,
        },
        Employee {
            name: String::from("Bob"),
            score: 88,
            attendance: 21,
            department: Department::Sales,
        },
        Employee {
            name: String::from("Charlie"),
            score: 88,
            attendance: 17,
            department: Department::HR,
        },
        Employee {
            name: String::from("Diana"),
            score: 65,
            attendance: 20,
            department: Department::HR,
        },
        Employee {
            name: String::from("Eve"),
            score: 42,
            attendance: 15,
            department: Department::Management,
        },
    ];

    for emp in &employees {
        println!("{}:", emp.name);
        let (rating, bonus) = emp.rate();
        let special = emp.has_special_bonus();
        println!("  Rating: {}, Bonus: {}%, Special: {}",
            rating, bonus, special);
        println!();
    }
}

Resultado:

TEXT 📖 Somente leitura
Alice:
  [@ binding] score 97 captured for A+ rating
  Rating: A+, Bonus: 30%, Special: true

Bob:
  [@ binding] score 88 captured for A rating
  Rating: A, Bonus: 20%, Special: false

Charlie:
  [@ binding] score 88 captured for B rating
  Rating: B, Bonus: 10%, Special: false

Diana:
  Rating: C, Bonus: 5%, Special: false

Eve:
  [guard] score 42 is below 60, rating D
  Rating: D, Bonus: 0%, Special: true

Este exemplo demonstra de forma abrangente três técnicas avançadas de correspondência: @ armazena valores capturados para uso posterior; if utiliza guardas para adicionar condições adicionais (como requisitos de frequência); | utiliza o modo multimodo para permitir que diferentes intervalos compartilhem o mesmo ramo; e matches! utiliza uma macro para determinar de forma concisa “se pertence a uma das várias variantes”.


▶ Exemplo 2: Desmontando estruturas aninhadas e enums (Dificuldade ⭐⭐⭐)

RUST
// ============================================
// Nested Deconstruction: Matching Enums in Structures, Tuples in Enumerations
// ============================================

#[derive(Debug)]
enum TaskStatus {
    Pending,
    InProgress,
    Completed { finished_at: String, reviewer: String },
    Blocked { reason: String, blocked_by: String },
}

#[derive(Debug)]
struct Task {
    id: u32,
    title: String,
    status: TaskStatus,
    priority: u8,  // 1 (highest) to 5 (lowest)
}

fn analyze_task(task: &Task) {
    // Destructure the Task struct directly in match
    match task {
        // Multi-pattern: priority 1 or 2 with any status
        Task { priority: 1..=2, .. } => {
            println!("  [range] High priority task (level {})", task.priority);
        }
        // Destructure both Task and TaskStatus::Completed
        Task {
            id,
            title,
            status:
                TaskStatus::Completed {
                    finished_at,
                    reviewer,
                },
            priority,
        } => {
            println!("  [nested destructure] Task #{} '{}' completed by {} at {} (priority {})",
                id, title, reviewer, finished_at, priority);
        }
        // Destructure TaskStatus::Blocked with @ binding on reason
        Task {
            status:
                TaskStatus::Blocked {
                    reason,
                    blocked_by,
                },
            ..
        } => {
            println!("  [@ binding] Task '{}' blocked by {}: {}",
                task.title, blocked_by, reason);
        }
        // Match guard on enum variant
        Task {
            status: TaskStatus::InProgress,
            priority,
            ..
        } if *priority <= 3 => {
            println!("  [guard] Important in-progress task (priority {})", priority);
        }
        // Wildcard for remaining
        _ => {
            println!("  [wildcard] Task '{}': status {:?}", task.title, task.status);
        }
    }
}

fn main() {
    let tasks = vec![
        Task {
            id: 1,
            title: String::from("Security audit"),
            status: TaskStatus::Completed {
                finished_at: String::from("2026-07-01"),
                reviewer: String::from("Alice"),
            },
            priority: 1,
        },
        Task {
            id: 2,
            title: String::from("Update dependencies"),
            status: TaskStatus::Blocked {
                reason: String::from("Waiting for approval"),
                blocked_by: String::from("Manager"),
            },
            priority: 2,
        },
        Task {
            id: 3,
            title: String::from("Write documentation"),
            status: TaskStatus::InProgress,
            priority: 3,
        },
        Task {
            id: 4,
            title: String::from("Fix typo in README"),
            status: TaskStatus::Pending,
            priority: 5,
        },
    ];

    for task in &tasks {
        println!("Task #{}: {}", task.id, task.title);
        analyze_task(task);
        println!();
    }
}

Resultado:

TEXT 📖 Somente leitura
Task #1: Security audit
  [nested destructure] Task #1 'Security audit' completed by Alice at 2026-07-01 (priority 1)

Task #2: Update dependencies
  [range] High priority task (level 2)

Task #3: Write documentation
  [guard] Important in-progress task (priority 3)

Task #4: Fix typo in README
  [wildcard] Task 'Fix typo in README': status Pending

A desestruturação aninhada é um recurso poderoso da correspondência de padrões do Rust: é possível desestruturar structs, enums e tuplas simultaneamente dentro de um único ramo match. .. ignora os campos nos quais você não está interessado, e @ vincula e captura valores internos. Observe que Task { priority: 1..=2, .. } corresponde a tarefas com qualquer prioridade de 1 ou 2 — pois, embora Blocked venha depois no padrão, range corresponde primeiro às tarefas com prioridade=2.


▶ Exemplo 3: Combinando a macro matches! com if let (Dificuldade: ⭐⭐)

RUST
// ============================================
// matches! Macro: Simple Boolean Pattern Matching
// ============================================

#[derive(Debug, PartialEq)]
enum HttpStatus {
    Ok,
    NotFound,
    ServerError(u16),
    Redirect(u16),
}

/// Check if a status is a success (2xx).
fn is_success(status: &HttpStatus) -> bool {
    matches!(status, HttpStatus::Ok)
}

/// Check if a status is a server error (5xx).
fn is_server_error(status: &HttpStatus) -> bool {
    matches!(status, HttpStatus::ServerError(_))
}

/// Check if a status is a redirect (3xx) with specific code.
fn is_redirect_to(status: &HttpStatus, code: u16) -> bool {
    matches!(status, HttpStatus::Redirect(c) if *c == code)
}

/// Get status category using multiple matches! checks.
fn categorize(status: &HttpStatus) -> &'static str {
    if matches!(status, HttpStatus::Ok) {
        "Success"
    } else if matches!(status, HttpStatus::Redirect(301 | 302)) {
        "Temporary Redirect"
    } else if matches!(status, HttpStatus::Redirect(_)) {
        "Other Redirect"
    } else if matches!(status, HttpStatus::NotFound) {
        "Not Found (404)"
    } else if matches!(status, HttpStatus::ServerError(500..=599)) {
        "Server Error"
    } else {
        "Unknown"
    }
}

fn main() {
    let statuses = vec![
        HttpStatus::Ok,
        HttpStatus::NotFound,
        HttpStatus::Redirect(301),
        HttpStatus::Redirect(307),
        HttpStatus::ServerError(500),
        HttpStatus::ServerError(503),
    ];

    for status in &statuses {
        println!("{:?}:", status);
        println!("  is_success: {}", is_success(status));
        println!("  is_server_error: {}", is_server_error(status));
        println!("  is_redirect_to_301: {}", is_redirect_to(status, 301));
        println!("  category: {}", categorize(status));

        // if let with matches!-style pattern
        if let HttpStatus::ServerError(code) = status {
            println!("  >> Server error code: {}", code);
        }
        println!();
    }
}

Resultado:

TEXT 📖 Somente leitura
Ok:
  is_success: true
  is_server_error: false
  is_redirect_to_301: false
  category: Success

NotFound:
  is_success: false
  is_server_error: false
  is_redirect_to_301: false
  category: Not Found (404)

Redirect(301):
  is_success: false
  is_server_error: false
  is_redirect_to_301: true
  category: Temporary Redirect

Redirect(307):
  is_success: false
  is_server_error: false
  is_redirect_to_301: false
  category: Other Redirect

ServerError(500):
  is_success: false
  is_server_error: true
  is_redirect_to_301: false
  category: Server Error

ServerError(503):
  is_success: false
  is_server_error: true
  is_redirect_to_301: false
  category: Server Error

A macro matches! retorna um bool, que é adequado para correspondência de padrões em condições if. Ela suporta toda a sintaxe de padrões, incluindo guardas if, padrões múltiplos e correspondência de intervalos. Ao contrário de if let, matches! não vincula variáveis; ela apenas retorna true/false — é a opção mais concisa quando você precisa apenas avaliar uma condição sem recuperar um valor.


▶ Exemplo 4: Exercício abrangente — Avaliador de expressões (Dificuldade ⭐⭐⭐)

RUST
// ============================================
// Comprehensive Example: Implementing Expression Evaluation Using Nested Pattern Matching
// ============================================

#[derive(Debug, Clone)]
enum Expr {
    Number(f64),
    Add(Box<Expr>, Box<Expr>),
    Sub(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Neg(Box<Expr>),
}

fn eval(expr: &Expr) -> Option<f64> {
    match expr {
        Expr::Number(n) => Some(*n),
        Expr::Add(a, b) => Some(eval(a)? + eval(b)?),
        Expr::Sub(a, b) => Some(eval(a)? - eval(b)?),
        Expr::Mul(a, b) => Some(eval(a)? * eval(b)?),
        Expr::Div(a, b) => {
            let divisor = eval(b)?;
            if divisor == 0.0 { None } else { Some(eval(a)? / divisor) }
        }
        Expr::Neg(a) => Some(-eval(a)?),
    }
}

fn expr_to_string(expr: &Expr) -> String {
    match expr {
        Expr::Number(n) => format!("{:.0}", n),
        Expr::Add(a, b) => format!("({} + {})", expr_to_string(a), expr_to_string(b)),
        Expr::Sub(a, b) => format!("({} - {})", expr_to_string(a), expr_to_string(b)),
        Expr::Mul(a, b) => format!("({} * {})", expr_to_string(a), expr_to_string(b)),
        Expr::Div(a, b) => format!("({} / {})", expr_to_string(a), expr_to_string(b)),
        Expr::Neg(a) => format!("-{}", expr_to_string(a)),
    }
}

fn main() {
    let expr1 = Expr::Add(
        Box::new(Expr::Number(10.0)),
        Box::new(Expr::Mul(Box::new(Expr::Number(3.0)), Box::new(Expr::Number(4.0)))),
    );
    let expr2 = Expr::Div(
        Box::new(Expr::Sub(Box::new(Expr::Number(20.0)), Box::new(Expr::Number(5.0)))),
        Box::new(Expr::Number(3.0)),
    );
    let expr3 = Expr::Neg(Box::new(Expr::Number(42.0)));
    let expr4 = Expr::Div(Box::new(Expr::Number(10.0)), Box::new(Expr::Number(0.0)));

    let exprs = [expr1, expr2, expr3, expr4];
    for (i, expr) in exprs.iter().enumerate() {
        let s = expr_to_string(expr);
        match eval(expr) {
            Some(val) => println!("Expression{}: {} = {:.2}", i + 1, s, val),
            None => println!("Expression{}: {} = Error (Division by Zero)", i + 1, s),
        }
    }
}

Resultado:

TEXT 📖 Somente leitura
Expression1: (10 + (3 * 4)) = 22.00
Expression2: ((20 - 5) / 3) = 5.00
Expression3: -42 = -42.00
Expression4: (10 / 0) = Error (Division by Zero)

A enumeração recursiva combinada com a desestruturação aninhada é uma das aplicações mais poderosas da correspondência de padrões. Box<Expr> Permite que as enumerações se referenciem a si mesmas (já que Box é um ponteiro de tamanho fixo). eval Utiliza o operador ? para propagar erros diferentes de zero de maneira elegante.


▶ Exemplo 5: Correspondência de padrões e estruturas de dados semelhantes a JSON (Dificuldade ⭐⭐⭐)

RUST
// ============================================
// Processing Dynamically Typed Data Using Pattern Matching
// ============================================

#[derive(Debug, Clone)]
enum Value {
    Null,
    Bool(bool),
    Number(f64),
    String(String),
    Array(Vec<Value>),
    Object(Vec<(String, Value)>),
}

fn type_name(val: &Value) -> &str {
    match val {
        Value::Null => "null",
        Value::Bool(_) => "bool",
        Value::Number(_) => "number",
        Value::String(_) => "string",
        Value::Array(_) => "array",
        Value::Object(_) => "object",
    }
}

fn deep_count(val: &Value) -> usize {
    match val {
        Value::Array(items) => items.iter().map(deep_count).sum::<usize>() + 1,
        Value::Object(entries) => entries.iter().map(|(_, v)| deep_count(v)).sum::<usize>() + 1,
        _ => 1,
    }
}

fn find_key<'a>(val: &'a Value, key: &str) -> Option<&'a Value> {
    match val {
        Value::Object(entries) => entries.iter().find(|(k, _)| k == key).map(|(_, v)| v),
        _ => None,
    }
}

fn main() {
    let data = Value::Object(vec![
        ("name".into(), Value::String("Alice".into())),
        ("age".into(), Value::Number(30.0)),
        ("active".into(), Value::Bool(true)),
        ("scores".into(), Value::Array(vec![
            Value::Number(95.0),
            Value::Number(88.0),
            Value::Number(92.0),
        ])),
        ("address".into(), Value::Object(vec![
            ("city".into(), Value::String("Beijing".into())),
            ("zip".into(), Value::Number(100000.0)),
        ])),
    ]);

    println!("Type: {}", type_name(&data));
    println!("Number of nodes: {}", deep_count(&data));

    if let Some(Value::String(name)) = find_key(&data, "name") {
        println!("Name: {}", name);
    }

    if let Some(Value::Array(scores)) = find_key(&data, "scores") {
        let avg: f64 = scores.iter()
            .filter_map(|v| if let Value::Number(n) = v { Some(*n) } else { None })
            .sum::<f64>() / scores.len() as f64;
        println!("Average Score: {:.1}", avg);
    }

    if let Some(Value::Object(addr)) = find_key(&data, "address") {
        if let Some(Value::String(city)) = find_key(&Value::Object(addr.clone()), "city") {
            println!("City: {}", city);
        }
    }
}

Resultado:

TEXT 📖 Somente leitura
Type: object
Number of nodes: 11
Name: Alice
Average Score: 91.7
City: Beijing

Use enumerações para simular dados de tipagem dinâmica (como JSON) e extraí-los e iterar sobre eles com segurança por meio da correspondência de padrões. find_key Use if let para acesso seguro e filter_map combinado com a correspondência de padrões para filtrar e transformar valores em um array.


❓ Perguntas Frequentes

P: Como é determinada a precedência entre uma condição match (if guard) e um desvio match? R: Uma condição match é uma condição dentro de um desvio — primeiro ocorre a correspondência do padrão e, em seguida, a condição é avaliada. Se a condição retornar false, o programa prossegue para o próximo ramal (não passa diretamente para o seguinte!). As variáveis vinculadas à correspondência de padrão podem ser usadas na condição de guarda.

P: Qual é a diferença entre a ligação com @ e o uso direto de uma variável? R: A ligação com @ captura um valor ao corresponder a um padrão específico. Por exemplo, e @ 1..=10 significa “se o valor estiver entre 1 e 10, atribua esse valor a e”. Escrever x corresponde diretamente a qualquer valor e o atribui a x. @ permite restringir o intervalo sem deixar de usar esse valor.

P: Qual é a diferença entre .. e _ na correspondência de padrões? R: .. corresponde a qualquer número de elementos (e os ignora), enquanto _ corresponde a uma única posição. Ao desestruturar uma estrutura, Struct { a, .. } ignora todos os outros campos; em uma tupla, (x, .., z) corresponde ao primeiro e ao último elementos. _ ignora apenas uma posição. .. só pode ser usado uma vez no mesmo padrão.

P: Qual é a diferença entre a macro matches! e if let? R: matches! retorna um bool (sem atribuir a uma variável), enquanto if let atribui a uma variável e executa o bloco de código. Se você precisar apenas verificar “se há correspondência”, sem precisar do valor correspondente, use matches!. Se precisar extrair o valor e usá-lo, use if let ou match.

P: Multimodo | É possível usá-lo com diferentes variantes de enumeração? R: Sim, mas as variantes devem ter o mesmo tipo e o mesmo número de elementos de dados (ou nenhum). Por exemplo, Some(1) | Some(2) é aceitável, mas Some(1) | None não é, porque Some possui elementos de dados, enquanto None não possui.

P: Quais tipos são compatíveis com a correspondência de intervalo ..=? R: São compatíveis qualquer tipo inteiro que implemente PartialOrd (i8-u128, u8-u128) e o tipo char. Por exemplo, match c { 'a'..='z' => "lowercase", 'A'..='Z' => "uppercase", _ => "other" }. A correspondência de intervalo para f64 não é compatível.


📖 Resumo


📝 Exercícios

  1. Dificuldade ⭐: Escreva uma função fn describe_number(n: i32) -> &'static str que utilize match e a comparação de intervalos: 1..=10 retorna “pequeno”, 11..=100 retorna “médio”, 101..=1000 retorna “grande” e todos os outros retornam “fora do intervalo”. Teste com os valores 5, 50, 500 e 5000 na função main.

  2. Dificuldade ⭐⭐: Defina uma enumeração Temperature que inclua duas variantes: Celsius(f64) e Fahrenheit(f64). Escreva uma função fn describe_temp(temp: &Temperature) -> &'static str que utilize a macro matches! e a condição if para determinar: se a temperatura em Celsius for maior que 30 ou em Fahrenheit for maior que 86, retorne “quente”; se a temperatura em Celsius for menor que 0 ou em Fahrenheit for menor que 32, retorne “frio”; caso contrário, retorne “moderado”. Teste as quatro temperaturas na função main.

  3. Dificuldade ⭐⭐⭐: Defina uma estrutura Order que contenha id: u32, items: Vec<String>, total: f64 e status: OrderStatus (enumeração: Pending, Shipped { tracking: String }, Delivered { date: String }). Implemente um método fn summary(&self) -> String que utilize desestruturação aninhada e guardas match para retornar diferentes mensagens de resumo com base no status e no valor total (por exemplo, para pedidos enviados cujo valor total seja superior a 1.000, exiba “Pedido de alto valor enviado, rastreamento: xxx”). Na função main, crie três pedidos e imprima seus resumos.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%