Skip to content

Functions

Use fn to declare a function. Every parameter must have an explicit type annotation — the compiler does not infer parameter types. The return type follows ->.

fn add(a: i32, b: i32) -> i32 {
a + b
}

Functions can be defined before or after they are used — Rust does not require forward declarations.

This is the most important distinction in Rust function bodies:

  • A statement performs an action and does not produce a value. let x = 5; is a statement — it ends with a semicolon.
  • An expression evaluates to a value. 5 + 3 is an expression. Blocks { ... } are expressions too.
fn main() {
// This is a statement — no value produced
let y = 6;
// This is an expression block — produces 12
let z = {
let x = 3;
x * 4 // no semicolon — this is the block's value
};
println!("y={}, z={}", y, z);
}

Adding a semicolon to the last line of a block converts it from an expression to a statement — the block now returns the unit type () instead of the computed value.

The last expression in a function body — written without a semicolon — is the return value. You can also use the return keyword for early returns, but idiomatic Rust prefers the trailing expression for the main return path.

fn square(n: i32) -> i32 {
n * n // returned because it has no semicolon
}
fn max_of_two(a: i32, b: i32) -> i32 {
if a > b { a } else { b } // if is an expression
}

Functions that do not return a meaningful value implicitly return () (the unit type). The signature fn foo() is shorthand for fn foo() -> (). The unit type is similar to void in other languages but is a real type with exactly one value: ().

fn greet(name: &str) {
// implicitly returns ()
println!("Hello, {}!", name);
}
fn add(a: i32, b: i32) -> i32 {
a + b // trailing expression -- no semicolon -- is the return value
}
fn describe(n: i32) -> &'static str {
if n > 0 { "positive" } else if n < 0 { "negative" } else { "zero" }
}
fn unit_example() {
// Functions without -> return the unit type ()
println!("unit example");
}
fn main() {
let sum = add(3, 4);
println!("add(3, 4) = {}", sum);
println!("describe(10) = {}", describe(10));
println!("describe(-3) = {}", describe(-3));
println!("describe(0) = {}", describe(0));
unit_example();
}
What is the return value of a function whose last line is n * 2 (no semicolon)?
What happens if you add a semicolon to the last expression in a function body?
Which of the following is true about function parameter types in Rust?
What is the unit type () in Rust?