Funções & Expressões
Rust é orientada a expressões: a maioria das construções avalia para um valor. Funções, blocos, if e match são expressões. Declarações (let, linhas terminadas com ;) realizam ações sem produzir valores externos.
Receita
fn square(n: i32) -> i32 {
n * n
}
fn max(a: i32, b: i32) -> i32 {
if a > b { a } else { b }
}
fn main() {
let result = {
let x = 4;
square(x) + 1
};
println!("{result}");
}Quando usar isso: Estruturar a lógica em funções pequenas e compositivas e usar blocos para escopar valores intermediários.
Exemplo Funcional
fn classify(score: u32) -> &'static str {
match score {
0..=49 => "fail",
50..=79 => "pass",
_ => "honors",
}
}
fn report(scores: &[u32]) -> String {
let mut lines = String::new();
for (i, &s) in scores.iter().enumerate() {
let label = classify(s);
lines.push_str(&format!("student {}: {label}\n", i + 1));
}
lines
}
fn main() {
println!("{}", report(&[88, 42, 65]));
}O que isso demonstra:
- Faixas de
matchcomo uma expressão retornando&str - Expressão de bloco em
reportconstruindo umaString - Parâmetro de slice
&[u32]aceita arrays eVec - Funções compõem sem classes ou métodos (métodos vêm depois)
Mergulho Profundo
Como Funciona
- Assinaturas de função exigem tipos de parâmetro; tipo de retorno após
-> - O corpo da função é uma expressão de bloco
return expr;sai antecipadamente; expressão final omitereturn- Um ponto e vírgula após a última expressão retorna
()em vez do valor
Declarações vs. Expressões
let x = 5; // declaração
5 + 1 // expressão, avalia para 6
{ let y = 3; y + 1 } // expressão de bloco -> 4Funções Divergentes
fn die(msg: &str) -> ! {
panic!("{msg}");
}O tipo de retorno ! significa que a função nunca retorna (panic, loop, exit).
Prévia de Closures
let add_one = |x| x + 1;
let doubled: Vec<_> = [1, 2, 3].iter().map(|n| n * 2).collect();Closures capturam variáveis de seu ambiente. Cobertura completa está na seção Closures.
Armadilhas
- Ponto e vírgula na última linha -
fn id(x: i32) -> i32 { x; }retorna()e falha na compilação. Correção: Remova o;final. - Tipos de braço
ifincompatíveis -if cond { 1 } else { "two" }gera erro. Correção: Retorne o mesmo tipo de todos os braços ou use coerção explícita. - Retornar referências a locais -
fn bad() -> &str { let s = String::from("x"); &s }falha na verificação de empréstimo. Correção: RetorneStringpossuída ou receba entrada por referência. - Sombreamento de nomes de parâmetros - Legal, mas confuso. Correção: Use nomes distintos dentro do corpo.
- Uso excessivo de
return-returndispersos escondem o fluxo natural da expressão. Correção: Usereturnantecipado apenas para guardas; caso contrário, use uma expressão final.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Closure | Callback curto passado para um iterador | Lógica reutilizada em muitos lugares |
| Método em struct | Comportamento ligado a dados | Funções livres são suficientes para utilitários |
| Macro | Padrões de sintaxe repetidos | Uma função simples funciona |
const fn | Avaliação em tempo de compilação necessária | Lógica apenas em tempo de execução |
FAQs
Funções podem retornar múltiplos valores?
Retorne uma tupla, struct ou use parâmetros de saída via &mut. Tuplas são boas para 2-3 valores relacionados.
O que é o tipo unit `()`?
A tupla vazia. main pode retornar () ou Result / ExitCode em binários.
Parâmetros são imutáveis por padrão?
Sim. Use mut param apenas se você reatribuir a ligação local dentro da função.
Posso sobrecarregar funções?
Não. Nomes diferentes ou traits genéricos fornecem polimorfismo em vez disso.
O que é um `if` orientado a expressão?
let v = if cond { a } else { b }; atribui o resultado do ramo a v.
Como passo um ponteiro de função?
fn(i32) -> i32 é um tipo de ponteiro de função. Closures com capturas precisam de traits Fn ou Box<dyn Fn>.
Blocos podem conter declarações e ainda serem expressões?
Sim. Apenas a expressão final (sem ;) se torna o valor do bloco.
Qual o status da recursão de cauda?
Rust não garante otimização de chamada de cauda. Prefira loops para recursão profunda.
Como documento funções?
Use comentários de documentação /// acima do item. Eles suportam Markdown e aparecem em cargo doc.
Pode `main` retornar `Result`?
Sim. fn main() -> Result<(), Box<dyn std::error::Error>> propaga erros com ?.
Relacionados
- Fluxo de Controle - loops e blocos rotulados
- Noções Básicas de Rust - primeiro tour de funções
- Noções Básicas de Closures - funções anônimas
- Noções Básicas de Traits - comportamento como traits
Versões da Pilha: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.