Funções em Rust
Uma função é um bloco de código com nome que você pode reaproveitar. Em vez de escrever os mesmos passos de novo e de novo, você os coloca uma vez em uma função e a chama sempre que precisar. Você já vem usando uma: a main.
Definindo e chamando uma função
Seção intitulada “Definindo e chamando uma função”Você define uma função com fn e a chama escrevendo o nome dela seguido de ():
fn greet() { println!("Olá de dentro de uma função!");}
fn main() { greet(); // chama a função greet(); // chama de novo}Saída:
Olá de dentro de uma função!Olá de dentro de uma função!Parâmetros: passando dados para a função
Seção intitulada “Parâmetros: passando dados para a função”As funções ficam úteis de verdade quando você passa dados para elas trabalharem. Essas entradas se chamam parâmetros. Em Rust, você precisa escrever o tipo de cada parâmetro:
fn greet(name: &str) { println!("Olá, {name}!");}
fn main() { greet("Alice"); greet("Bob");}Saída:
Olá, Alice!Olá, Bob!Você pode ter quantos parâmetros precisar, separados por vírgulas:
fn describe(name: &str, age: u32) { println!("{name} tem {age} anos");}
fn main() { describe("Ferris", 10);}Saída:
Ferris tem 10 anosOs valores que você passa são ligados aos parâmetros pela posição: o primeiro valor vai para name, o segundo para age. Passá-los na ordem errada, como em describe(10, "Ferris"), é um erro de compilação, porque os tipos não combinam.
Retornando um valor
Seção intitulada “Retornando um valor”Uma função pode devolver um valor para quem a chamou. Você declara o tipo de retorno depois de uma seta ->:
fn add(a: i32, b: i32) -> i32 { a + b}
fn main() { let sum = add(3, 4); println!("3 + 4 = {sum}");}Saída:
3 + 4 = 7A regra do ponto e vírgula (importante!)
Seção intitulada “A regra do ponto e vírgula (importante!)”Repare que o a + b no exemplo acima não tem ponto e vírgula. Essa é uma ideia central do Rust:
- Uma expressão sem ponto e vírgula é o valor que será retornado.
- Colocar um ponto e vírgula a transforma em uma instrução que não retorna nada.
Então isto quebra:
fn add(a: i32, b: i32) -> i32 { a + b; // ❌ o ponto e vírgula quer dizer "não retorne nada", mas prometemos um i32}O compilador vai reclamar que a função deveria retornar um i32, mas não retorna. É só tirar o ponto e vírgula da última linha.
Juntando tudo
Seção intitulada “Juntando tudo”fn square(n: i32) -> i32 { n * n}
fn main() { let result = square(5); println!("5 ao quadrado é {result}");}Saída:
5 ao quadrado é 25Prática
Seção intitulada “Prática”1. Celsius para Fahrenheit
Seção intitulada “1. Celsius para Fahrenheit”Escreva uma função to_fahrenheit que recebe uma temperatura em Celsius como f64 e a devolve em Fahrenheit. A fórmula é c * 9.0 / 5.0 + 32.0. Chame a função para 0, 100 e 37 graus. Dica: a assinatura é fn to_fahrenheit(c: f64) -> f64, e o corpo é uma única expressão sem ponto e vírgula.
Ver solução
fn to_fahrenheit(c: f64) -> f64 { c * 9.0 / 5.0 + 32.0}
fn main() { println!("0°C são {}°F", to_fahrenheit(0.0)); println!("100°C são {}°F", to_fahrenheit(100.0)); println!("37°C são {}°F", to_fahrenheit(37.0));}Saída:
0°C são 32°F100°C são 212°F37°C são 98.6°FRepare que passamos 0.0, e não 0. O parâmetro é um f64, e o Rust não transforma um inteiro em número de ponto flutuante por conta própria. Quando um f64 não tem parte fracionária, o {} o imprime sem o .0, e é por isso que aparece 32 e não 32.0. Note também que o Rust usa ponto como separador decimal: 98.6.
2. O maior de três
Seção intitulada “2. O maior de três”Escreva uma função largest(a: i32, b: i32, c: i32) -> i32 que devolve o maior dos três números. Teste com (3, 9, 4) e (-2, -8, -5). Dica: o if é uma expressão em Rust (veja If…Else), então uma cadeia de if / else if / else pode ser a última linha da função.
Ver solução
fn largest(a: i32, b: i32, c: i32) -> i32 { if a >= b && a >= c { a } else if b >= c { b } else { c }}
fn main() { println!("{}", largest(3, 9, 4)); println!("{}", largest(-2, -8, -5));}Saída:
9-2Nenhum dos ramos termina com ponto e vírgula. Cada um é uma expressão, a cadeia de if inteira devolve um deles, e esse vira o valor de retorno. Usar >= em vez de > garante que, em caso de empate, a função ainda devolva um valor.
- Defina funções com
fne chame-as comnome(). - Parâmetros são entradas, e cada um precisa de um tipo:
fn greet(name: &str). - Declare o tipo de retorno com
-> Tipo. - A última expressão sem ponto e vírgula é o valor de retorno.
return valor;também funciona, mas costuma ser usado só para retornar mais cedo.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Em Rust, é preciso escrever o tipo de cada parâmetro de uma função?
2. Como se declara o tipo de retorno de uma função?
3. Por que a + b (sem ponto e vírgula) no fim de uma função vira o valor de retorno?
4. Faz diferença definir uma função acima ou abaixo de onde ela é chamada (por exemplo, acima ou abaixo da main)?
Pontuação: 0 / 4
Para saber mais
Seção intitulada “Para saber mais”- Functions — The Rust Book (em inglês): o capítulo oficial sobre parâmetros, valores de retorno e instruções versus expressões.
- Statements and Expressions — The Rust Book (em inglês): um olhar mais de perto na ideia por trás da regra do ponto e vírgula.
- Functions — Rust by Example (em inglês): exemplos executáveis, incluindo
returnantecipado e funções que não retornam nada. - Functions — The Rust Reference (em inglês): as regras exatas de como funções são definidas, para quando você quiser os detalhes.
- A palavra-chave
fn— documentação da std (em inglês): um resumo curto da sintaxe de funções, com exemplos.