Rust :: Patterns and Flows

Patterns and Flow of Controls

Patterns

if

// Rust does not auto convert non-bool to bool
// expression needs to return a Bool
if expression {
    statements;
} else if expression {
    statements;
} else {
    statements;
}

// if is an expression
// needs to be same type
let num = if condition { 5 } else { 6 };

loop

loop {
    statements;
    break return_value;
}
// using 'label in loop
    'outer: loop {
        println!("Entered the outer loop");
        'inner: loop {
            println!("Entered the inner loop");
            // This would break only the inner loop
            //break;
            // This breaks the outer loop
            break 'outer;
        }

//while
while expression {
    statements;
}

//for
// iterable: std::iter::IntoIterator trait
for pattern in iterable {
    block
}

for element in (1..4).rev() {
    statements;
}

// takes ownership
for item in collection
for item in IntoIterator::into_iter(collection)

// read-only
for item in &collection
for item in collection.iter()

// modify item
for item in &mut collection
for item in collection.iter_mut()


// range
a..b // inclusive a, exclusive b
a..=b //inclusive both

// try to use iterable chain fn rather than for
// example
let mut x = String::new();
for i in 1..64 {
   x = x + "\n" + some_fn(i);
}
// use iterable
(1..64).map(|x| some_fn(x)).collect::<Vec<String>>().join("\n"); 

match

// all possible values (called arm) must be covered
// comp to if: expression can return any type
// ..= inclusive range, 'a'..='j'
match expr {
    pattern => expr,
    ...
}

match number {
    1 => println!("One"),
    2 | 3 | 4 => println!("Some"),
    12..=19 => { 
        println!("Curly brackets for long code");
    } // no , with {}
    _ => println!("Catch all"),
}
match value {
    val => println!("value: {:?}", val),
}
// match guards
// must have catch all
// use _ to ignore values
// _var to silent warning of non used var
    let pair = (2, -2);
    match pair {
        (x, y) if x == y => println!("These are twins"),
        (x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
        (x, _) if x % 2 == 1 => println!("The first one is odd"),
        _ => println!("No correlation..."),
    }
// binding
    match age() {
        0             => println!("I haven't celebrated my first birthday yet"),
        // Could `match` 1 ..= 12 directly but then what age
        // would the child be? Instead, bind to `n` for the
        // sequence of 1 ..= 12. Now the age can be reported.
        n @ 1  ..= 12 => println!("I'm a child of age {:?}", n),
        n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
        // Nothing bound. Return the result.
        n             => println!("I'm an old person of age {:?}", n),
    }

// match an enum
match some_enum {
    SomeEnum::Var1 => // do something
    SomeEnum::Var2(s) => println!("{}",s),
    _ => // do something
}

// ignore some fileds with ..
match some_struct {
    SomeStruct { x, .. } => println!("{:?}", x),
}
match some_tuple {
    (first, .., last) => /* do something */
}

if let

if let pattern = expr {
    block1
} else {
    block2
}
// same as
match expr {
    pattern => { block 1 }
    _ => { block2 }
}

// example
    if let Some(i) = option_value {
        // i is valid, do something 
    } else {
        // option_value is None
    }

// use `if let` in Enum
enum Foo {
    Bar,
    Qux(i32),
}
let a = Foo::Bar;
let c = Foo::Qux(100);
if let Foo::Bar = a {
    // note Foo::Bar is on the left side
} else if let Foo::Qux(v) = c {
    println!("{}", v);
}

while let

    while let Some(i) = vec.pop() {
        // .pop() is Option<T>
    }