Funções em Rust
Esta aula aborda funções em Rust, incluindo declaração, parâmetros com tipos, retorno de valores e a diferença entre statements e expressions. Você aprenderá a criar funções reutilizáveis e entenderá como Rust trata expressões para retorno implícito.
Funções são blocos de código reutilizáveis que realizam tarefas específicas. Em Rust, as funções são declaradas com a palavra-chave fn e seguem uma sintaxe clara e tipada. Nesta aula, exploraremos como declarar funções, passar parâmetros, retornar valores e entender a diferença fundamental entre statements e expressions, que influencia diretamente como escrevemos código funcional em Rust.
Rust é uma linguagem que valoriza a clareza e a segurança. As funções ajudam a organizar o código, evitar repetição e encapsular lógica. Além disso, Rust trata funções como cidadãs de primeira classe, permitindo passá-las como argumentos e retorná-las de outras funções, mas isso será abordado em aulas futuras. Por enquanto, focaremos nos fundamentos.
Declaração
Para declarar uma função em Rust, usamos a palavra-chave fn seguida do nome da função, parênteses para os parâmetros (que podem ser vazios) e um bloco de código entre chaves. O nome da função deve estar em snake_case (letras minúsculas e underscores).
Exemplo de função simples que imprime uma mensagem:
fn saudacao() {
println!("Olá, mundo!");
}Para chamar a função, basta usar seu nome seguido de parênteses:
fn main() {
saudacao();
}A ordem das funções não importa; você pode definir saudacao antes ou depois de main. Rust procura a função pelo nome em todo o escopo do módulo.
Parâmetros e tipos
Funções podem receber parâmetros, que são valores passados para a função. Cada parâmetro deve ter seu tipo explicitamente declarado. A sintaxe é: nome: Tipo. Múltiplos parâmetros são separados por vírgulas.
Exemplo de função que soma dois números:
fn soma(a: i32, b: i32) {
println!("A soma é {}", a + b);
}Chamando a função:
fn main() {
soma(5, 3);
}Os parâmetros são vinculados aos argumentos passados. Rust é fortemente tipado, então os tipos devem corresponder. Você também pode passar referências ou outros tipos compostos, mas isso será visto em aulas posteriores.
Retorno e expressões
Funções podem retornar valores. O tipo de retorno é especificado após uma seta (->). Para retornar um valor, usamos a palavra-chave return ou, mais idiomático, a última expressão do bloco (sem ponto e vírgula).
Exemplo com return explícito:
fn dobro(x: i32) -> i32 {
return x * 2;
}Exemplo com retorno implícito (última expressão):
fn dobro(x: i32) -> i32 {
x * 2
}Note que não há ponto e vírgula no final de x * 2. Se colocássemos ponto e vírgula, a linha se tornaria um statement (que não retorna valor) e causaria um erro de tipo, pois a função espera um i32.
Funções que não retornam valor explicitamente têm tipo de retorno () (tupla vazia), que pode ser omitido.
Statements vs expressions
Em Rust, a distinção entre statements e expressions é crucial. Um statement é uma instrução que realiza uma ação, mas não produz um valor. Exemplos: declaração de variável com let, chamada de função com ponto e vírgula, etc. Uma expression é algo que avalia para um valor. Exemplos: 5 + 3, if condicao { valor } else { outro }, bloco de código.
A última expressão de um bloco (como o corpo de uma função ou um bloco {}) é retornada como valor do bloco. Statements não retornam valor, então não podem ser usados como última expressão se a função espera um retorno.
Exemplo de expressão com if:
fn maior(a: i32, b: i32) -> i32 {
if a > b { a } else { b }
}Aqui, o if é uma expressão que retorna a ou b. Note que não há ponto e vírgula.
Já um let é um statement:
let x = 5; // statement, não retorna valorEntender essa diferença ajuda a escrever código mais conciso e idiomático em Rust.
Boas práticas e observações
Prefira usar retorno implícito quando a função for pequena e clara. Use return para saídas antecipadas (ex: em validações). Sempre declare os tipos dos parâmetros e do retorno, exceto quando o retorno for (). Nomes de funções devem ser descritivos e em snake_case. Evite funções muito longas; quebre em funções menores.
Referências
- The Rust Programming Language - Functions
- Rust by Example - Functions
- Rust Reference - Functions
- Statements and Expressions in Rust Book
- Rust std::keyword::fn
Exercícios
Crie uma função chamada
quadradoque recebe um número inteiro e retorna seu quadrado. Use retorno implícito.✓ Resposta:fn quadrado(x: i32) -> i32 { x * x }Escreva uma função
saudacao_personalizadaque recebe um nome (string slice&str) e imprime "Olá, [nome]!".✓ Resposta:fn saudacao_personalizada(nome: &str) { println!("Olá, {}!", nome); }Implemente uma função
eh_parque recebe um número e retornatruese for par,falsecaso contrário.✓ Resposta:fn eh_par(n: i32) -> bool { n % 2 == 0 }Crie uma função
maximoque recebe dois números e retorna o maior. Use a expressãoif.✓ Resposta:fn maximo(a: i32, b: i32) -> i32 { if a > b { a } else { b } }Explique por que o código abaixo não compila e corrija-o:
fn exemplo() -> i32 { let x = 5; x; }✓ Resposta:O código não compila porque a última linhax;é um statement (devido ao ponto e vírgula) e não retorna valor. A função espera retornari32. A correção é remover o ponto e vírgula:fn exemplo() -> i32 { let x = 5; x }. Assim,xé a última expressão e retorna o valor.