As funções são blocos de código que contêm uma ou mais instruções ou expressões. Uma função pode, opcionalmente, devolver um valor.
Em Rust, o estilo é usar snake case para o nome de uma função, que é precedido pela palavra-chave fn numa definição de função. Por exemplo
fn do_nothing() {}
Os parênteses envolvem zero ou mais parâmetros, separados por vírgulas. Um parâmetro é uma ligação a um valor de um determinado tipo que é passado para a função. Mesmo que não haja parâmetros, os parênteses continuam a ser obrigatórios na definição da função. O valor efetivamente passado a um parâmetro chama-se argumento.
A combinação de parâmetros e do valor devolvido é conhecida como a assinatura da função. A assinatura de uma função exige que cada parâmetro tenha o tipo anotado.
As chavetas delimitam o corpo da função: as suas instruções e expressões. Mesmo que a função não contenha instruções ou expressões, as chavetas continuam a ser obrigatórias na definição da função.
No exemplo seguinte, a função recebe um parâmetro do tipo i32, liga-o ao nome value e imprime-o.
fn print_integer(value: i32) {
println!("{value:?}");
}
Repara na definição do parâmetro. Cada parâmetro é definido no formato name: Type.
Uma função também pode devolver um valor. Por predefinição, é devolvido o resultado da expressão final.
No exemplo seguinte, a função tem um parâmetro i32 e devolve o seu dobro.
fn double_integer(value: i32) -> i32 {
value * 2
}
O -> i32 indica que a função devolve um i32. Ao contrário dos parâmetros, o valor devolvido não tem nome.
É possível sair de uma função antecipadamente com a palavra-chave return, assim:
fn long_function() -> i32 {
let some_condition = false;
// code snipped
if (some_condition) {
return 0;
}
// more code snipped
42
}
const fn é usado para definir uma função constante, que pode ser avaliada em tempo de compilação.
const fn compute_data_checksum() -> u128 {
const DATA: &[u8] = include_bytes!("my_big_data_file");
// checksum implementation is left as an exercise for the reader
}
/// This checksum is used to validate that the user has not tampered with proprietary configuration.
pub const DATA_CHECKSUM: u128 = compute_data_checksum();
Como as funções constantes podem ser avaliadas em tempo de compilação, têm algumas restrições que as funções normais não têm.
Em particular, uma const fn só pode chamar outras funções também marcadas como const. O incumprimento dessa restrição resulta num
erro de compilação.
const fn multiply_integer(value: i32) -> i32 {
use std::time::SystemTime;
if SystemTime::now().elapsed().unwrap().as_nanos() == 0 { // this line errors
value * 2
} else {
value * 3
}
}
Existem funções anónimas, que são abordadas no tópico closures.