Functions

Functions are defined using the fn keyword, followed by whatever name you want to give your function.

1
2
3
4
fn next_birthday( name: &str, current_age: u8 ) {
    let next_age = current_age + 1;
    println!("Hi {}, on your next birthday you'll be {}!", name, next_age );
}

Within parentheses, list each parameter the function takes by giving the parameter name, then a colon, then specifying the type of that parameter. Separate each name/type pair with a comma.

If the function returns a value, put an arrow ( -> ), and then specify the type of the return value. If the function doesn’t return a value, leave off the arrow and the return type.

Then, open a set of curly brackets, put the code you want to be the body of the function, and close the curly brackets.

There are more complicated function signatures possible, way more complicated!!

Also, there is a return keyword that you can use to return from a function early, and you can use it at the end of a function if you want. However, idiomatic style is to implicitly return the last expression.

1
2
3
fn next_age( current_age: u8 ) -> u8 {
    current_age + 1
}

If the last line in the body doesn’t have a semicolon at the end. This tells Rust we want the resulting value of that expression returned out of the function body.


Control Flow

if / else if / else

1
2
3
4
5
6
7
if expression {
   ...code...
} else if expression {
    ...code...
} else {
   ...code...
}

Like with functions, we can get a value from an if or else block by leaving the semicolon off of the last expression in the block.

1
2
3
4
5
let amount = if day_number % 2 == 0 {
    10
} else {
    20
};

Return from if else expression have some restrictions

  • We do need a semicolon to end the variable assignment statement.
  • There must be an else clause so that the variable always gets a value.
  • The types of the values must all be the same

loop, while, for

The loop keyword lets you specify a block of code that should be run forever.

1
2
3
loop {
   println!("Hello, notes!");
}

You can use the break keyword to exit a loop.

A while loop is written with the while keyword, then an expression that evaluates to true or false

1
2
3
while expression {
    ...code...
}

The code in the block runs over and over, while the expression specified is true.

The for loop is probably the most common loop in Rust code. It lets you run some code for each item in a collection. Unlike for loops in some other languages, like C, you don’t need to manage an index into the collection and worry about off-by-one errors.

1
2
3
for item in collection {
   ...code...
}

match

It’s sort of like a bunch of if/else ifs and sort of like a switch or case statement, but better for two reasons:

  • pattern matching

Pattern matching is a feature available in Rust in multiple places. For example, destructured a tuple into parts in the Data types module.

1
2
     let tup = ( 1, 'a', true );
     let (a,b,c) = tup;

Is especially useful in match expressions. We specify a list of patterns to test a value against, and the match expression tests the value against each pattern and stops if it finds a matching one.

1
2
3
4
5
6
7
    let x = 4;
    match x {
        1 => println!("Uno"),
        2 => println!("Dos"),
        3 => println!("Tres"),
        _ => println!("Rest of the numbers...")
    }

The underscore in the last pattern is a catch-all that will match any value. So the last arm functions like an else in a set of if/elseif/else blocks.

  • exhaustiveness

Must be exhaustive and cover every case. This prevents bugs that can be caused by forgetting to handle a situation.


Book chapters Functions / Control flow

Also posted in collected notes