Rust Functions
Declare and call functions in Rust, understand statements versus expressions, and return values with the arrow syntax.
Fourth post in the basic Rust series. Functions are how you name and reuse logic. Rust’s functions are simple — the key idea is that almost everything is an expression.
A first function#
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let result = add(3, 4);
println!("{result}"); // 7
}rustParameters declare their types; the return type comes after ->.
Statements vs expressions#
A statement performs an action and returns nothing. An expression evaluates to a value.
fn add(a: i32, b: i32) -> i32 {
let sum = a + b; // statement, ends with a semicolon
sum // expression, no semicolon
}rustThe last expression — without a semicolon — is the return value. If you add a semicolon, the function returns () instead.
Early return#
Use return to exit early:
fn is_adult(age: u32) -> bool {
if age >= 18 {
return true;
}
false
}rustNo return value#
A function that produces nothing has the unit type ():
fn greet(name: &str) {
println!("Hello, {name}!");
}rustThe implicit return type is ().
Passing ownership#
By default, passing a value to a function moves it (details in the next post on ownership):
fn print_len(s: String) {
println!("{}", s.len());
}
fn main() {
let s = String::from("hello");
print_len(s); // s is moved
// println!("{s}"); // error: s no longer exists
}rustGeneric functions#
Functions can be generic over types with angle brackets:
fn first<T>(list: &[T]) -> &T {
&list[0]
}rustT stands for any type. The compiler infers it from the call site.
Conclusion#
Rust functions are expressions all the way down: parameters are typed, the last expression is the return value, and ownership travels with values. Next in this series: ownership.