🎓 A1Learner
🔍

Rust Functions

A function is a named block of code that a program can run again and again. Values go in as parameters.

The same lines, written twice

Two greetings repeat the same welcome line. A change means editing every copy:

fn main() {
    println!("Hello, Ana!");
    println!("Welcome back.");
    println!("Hello, Bo!");
    println!("Welcome back.");
}

Write a function, then call it

fn declares a function. main has carried every program so far — your own functions work the same way:

fn say_hello() {
    println!("Hello from a function!");
}
say_hello();

Give it values: parameters

The names in the definition are parameters, and every parameter must name its type. The values you pass when calling are the arguments:

fn show(score: i32) {
    println!("score = {}", score);
}
show(90);

The last expression is the answer

The type after -> is the type the function gives back. The last expression in the body, with no semicolon, is that value:

fn double(n: i32) -> i32 {
    n * 2
}
println!("double = {}", double(21));

Leave early with return

Use the word return only when you want to leave before the end:

fn classify(n: i32) -> i32 {
    if n < 0 {
        return -1;
    }
    n
}
println!("{}", classify(-5));
println!("{}", classify(7));

No return type means ()

Leave the -> part out and the function gives back the unit value (). Writing -> () instead means exactly the same thing:

fn announce(score: i32) {
    println!("score = {}", score);
}
let got = announce(90);
println!("announce gave {:?}", got);

Example

fn celsius(f: f64) -> f64 {
    (f - 32.0) * 5.0 / 9.0
}
fn main() {
    println!("98.6F = {:.1}C", celsius(98.6));
}

Key points

  • Functions can be written in any order — Rust finds them all
  • Some functions never give back at all.
  • One example stops the program.
  • Their return type is the special !
  • Rust has no overloading: one name means one function.
  • You cannot write two functions with the same name.
  • Different inputs do not help.
  • Use two names instead.
  • Or use one function.
  • That function can take a tuple.
  • It can take an enum
  • A function always takes a fixed number of inputs.
  • Parameters have no default values.
  • Every call passes every value.
  • It passes them every time.
  • Macros such as println! are the escape hatch when a call needs a variable number of arguments
  • Every argument travels into the function in one of two ways.
  • It can travel by value.
  • Then the function receives the value itself.
  • It can travel by reference.
  • Then it borrows yours.
  • A function is one named block: every call runs the same block again.

In this example, celsius takes a decimal number f and gives back a decimal. The body is one expression: (f - 32.0) * 5.0 / 9.0. There is no semicolon, so this value is the answer. In main, celsius(98.6) is called, and {:.1} prints the result with one decimal digit: 37.0. Say you added a semicolon to that line. Then the function would give back nothing instead. The code would stop compiling.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What happens if you add a semicolon to the last expression of a function?