Rust Functions
Functions in Rust are declared with fn, require explicit type annotations on every parameter, and return the value of their final expression without needing a return keyword.
Declaring a Function
A function definition starts with fn, followed by a snake_case name, a parenthesized parameter list where every parameter has an explicit type, and an optional -> ReturnType. Unlike local variables, parameter and return types are never inferred.
A function with parameters and a return type
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let sum = add(3, 4);
println!("3 + 4 = {}", sum);
}Expression-Based Return Values
The last expression in a function body, written without a trailing semicolon, becomes the function's return value automatically. The explicit return keyword is still available and is typically reserved for early exits.
Mixing an early return with a tail expression
fn classify(n: i32) -> &'static str {
if n < 0 {
return "negative";
}
if n == 0 {
"zero"
} else {
"positive"
}
}
fn main() {
println!("{}", classify(-4));
println!("{}", classify(0));
println!("{}", classify(9));
}Functions Without a Return Value
A function returning the unit type
fn greet(name: &str) {
println!("Hello, {}!", name);
}
fn main() {
greet("Ferris");
}- Parameters and return types must always be explicitly annotated; only local variables get type inference.
- The final expression of a function body (no trailing semicolon) becomes its return value.
- return is only needed for early exits; idiomatic Rust relies on the implicit tail expression otherwise.
- A function with no -> Type returns (), Rust's empty-tuple unit type.
Exercise: Rust Functions
Do Rust function parameters need explicit type annotations?