Functions

fn foo(x: i32, unit_label: char) -> i32 {
    let y = {
        let z = 3;
        x + z // expression at the end of a block - no semi-colon
    };

    println!("The value of y is: {y}{unit_label}");
    y // returns y - no semi-colon
}

fn main() {
    println!("{}", foo(1, 'm'));
}

The unit type () (void in some languages) is the default return type when no type is given for a function. It could be omitted: fn log(message: &str) { ... }

Generic functions

fn generic<T>(_t: T) {
    println!("got t");
}

// Explicitly specified type parameter `char` to `generic()`. Note the
// turbofish notation ::<>
fn main() {
    generic::<char>('a');
}
use std::fmt::Display;

fn generic<T: ?Sized + Display>(t: &T) {
    // By default, generic functions will work only on types that have a
    // known size at compile time. Use ?Sized to relax that. t must be
    // some kind of pointer: &, Rc, Box...
    println!("{}", t);
}

fn main() {
    let s = String::from("hello");
    generic(&s[..]);
}

Function pointers

fn add_one(x: i32) -> i32 {
    x + 1
}

fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    // function pointer
    f(arg) + f(arg)
}

fn main() {
    println!("{}", do_twice(add_one, 1));
}

Diverging functions

Diverging functions never return.

fn foo() -> ! {
    // <-- empty type
    panic!("This call never returns.");
}

fn main() {
    println!("Will panic");
    foo();
}