Control Flow
Control Flow primitives
if
expressionsloop
andwhile
loopsmatch
expressionsfor
loopsbreak
andcontinue
return
and?
Using if
as a statement
- Tests if a boolean expression is
true
- Parentheses around the conditional are not necessary
- Blocks need brackets, no shorthand
fn main() { if 1 == 2 { println!("integers are broken"); } else if 'a' == 'b' { println!("characters are broken"); } else { println!("that's what I thought"); } }
Using if
as an expression
- Every block is an expression
- Note the final
;
to terminate thelet
statement.
fn main() { let x = if 1 == 2 { 100 } else if 'a' == 'b' { 200 } else { 300 }; }
Using if
as the final expression
Now the if
expression is the result of the function:
#![allow(unused)] fn main() { fn some_function() -> i32 { if 1 == 2 { 100 } else if 'a' == 'b' { 200 } else { 300 } } }
Looping with loop
loop
is used for (potentially) infinite loops
fn main() { let mut i = 0; loop { i += 1; if i > 100 { break; } } }
Looping with loop
loop
blocks are also expressions...
fn main() { let mut i = 0; let loop_result = loop { i += 1; if i > 10 { break 6; } println!("i = {}", i); }; println!("loop_result = {}", loop_result); }
while
while
is used for conditional loops.- Loops while the boolean expression is
true
fn main() { let mut i = 0; while i < 10 { i += 1; println!("i = {}", i); } }
Control Flow with match
- The
match
keyword does pattern matching - You can use it a bit like an
if/else if/else
expression - The first arm to match, wins
_
means match anything
fn main() { let a = 4; match a % 3 { 0 => { println!("divisible by 3") } _ => { println!("not divisible by 3") } } }
for
loops
for
is used for iteration- Here
0..10
creates aRange
, which you can iterate
fn main() { for num in 0..10 { println!("{}", num); } }
for
loops
Lots of things are iterable
fn main() { for ch in "Hello".chars() { println!("{}", ch); } }
for
under the hood
- What Rust actually does is more like...
- (More on this in the section on Iterators)
fn main() { let mut iter = "Hello".chars().into_iter(); loop { match iter.next() { Some(ch) => println!("{}", ch), None => break, } } }
Break labels
If you have nested loops, you can label them to indicate which one you want to break out of.
fn main() { 'cols: for x in 0..5 { 'rows: for y in 0..5 { println!("x = {}, y = {}", x, y); if x + y >= 6 { break 'cols; } } } }
Continue
Means go around the loop again, rather than break out of the loop
fn main() { 'cols: for x in 0..5 { 'rows: for y in 0..5 { println!("x = {}, y = {}", x, y); if x + y >= 4 { continue 'cols; } } } }
return
return
can be used for early returns- The result of the last expression of a function is always returned
#![allow(unused)] fn main() { fn get_number(x: bool) -> i32 { if x { return 42; } -1 } }