Funktionen sind Codeblöcke, die eine oder mehrere Anweisungen oder Ausdrücke enthalten. Eine Funktion kann optional einen Wert zurückgeben.
In Rust ist es üblich, Funktionsnamen in Snake Case zu schreiben. Bei einer Funktionsdefinition steht das Schlüsselwort fn davor. Zum Beispiel
fn do_nothing() {}
Die runden Klammern umschließen null oder mehr Parameter, die durch Kommas getrennt sind. Ein Parameter ist eine Bindung an einen Wert eines bestimmten Typs, der an die Funktion übergeben wird. Auch wenn es keine Parameter gibt, sind die runden Klammern in der Funktionsdefinition trotzdem erforderlich. Der tatsächliche Wert, der an einen Parameter übergeben wird, heißt Argument.
Die Kombination aus Parametern und Rückgabewert nennt man die Signatur der Funktion. In der Signatur einer Funktion muss für jeden Parameter der Typ angegeben werden.
Die geschweiften Klammern umschließen den Rumpf der Funktion: seine Anweisungen und Ausdrücke. Auch wenn die Funktion keine Anweisungen oder Ausdrücke enthält, sind die geschweiften Klammern für die Funktionsdefinition trotzdem erforderlich.
Im folgenden Beispiel nimmt die Funktion einen Parameter vom Typ i32 entgegen, bindet ihn an den Namen value und gibt ihn aus.
fn print_integer(value: i32) {
println!("{value:?}");
}
Achte auf die Definition des Parameters. Jeder Parameter wird im Format name: Type definiert.
Eine Funktion kann auch einen Wert zurückgeben. Standardmäßig wird der Wert des letzten Ausdrucks zurückgegeben.
Im folgenden Beispiel hat die Funktion einen Parameter vom Typ i32 und gibt dessen Doppeltes zurück.
fn double_integer(value: i32) -> i32 {
value * 2
}
Das -> i32 zeigt an, dass die Funktion einen i32 zurückgibt. Anders als Parameter hat der zurückgegebene Wert keinen Namen.
Mit dem Schlüsselwort return kannst du vorzeitig aus einer Funktion aussteigen, und zwar so:
fn long_function() -> i32 {
let some_condition = false;
// code snipped
if (some_condition) {
return 0;
}
// more code snipped
42
}
Mit const fn definierst du eine konstante Funktion, die zur Kompilierzeit ausgewertet werden kann.
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();
Da konstante Funktionen zur Kompilierzeit ausgewertet werden können, unterliegen sie einigen Einschränkungen, die für normale Funktionen nicht gelten.
Insbesondere kann eine const fn nur andere Funktionen aufrufen, die ebenfalls als const gekennzeichnet sind. Wenn du diese Einschränkung nicht einhältst,
kommt es zu einem Kompilierfehler.
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
}
}
Es gibt auch anonyme Funktionen; sie werden im Thema closures behandelt.