if let Bindings

The first concept is if let bindings, which you can read about here. This control flow construct allows us to check if the value of an expression matches some pattern, and bind it to a new variable if so. We can have an else branch on this if let statement as well.

We can check out a brief demo of this pattern on both Options and Results. In the code below, we have two Options and two Results. The first option is None, while the second is Some(T) (where T is String in this case). We can pattern match both of these variables using if let to bind them to a new variable if they match the pattern (Some(_)) that we are checking for. Notice in the first check, we bind x to a new variable x, and in the second we bind x to a new variable e. We can do the same for Result.

fn main() {
  let x: Option<String> = None;
  let y: Option<String> = Some("Hello, World!".to_string());

  if let Some(x) = x {
      println!("x is some: {}!", x);
  } else {
      println!("x is none");
  }

  if let Some(e) = y {
      println!("y is some: {}!", e);
  } else {
      println!("y is none");
  }

  let w: Result<String, String> = Err("There was something wrong...".into());
  let z: Result<String, String> = Ok("Hello, World!".to_string());

  if let Ok(z) = z {
      println!("z was ok: {}!", z);
  } else {
      println!("z was not ok");
  }

  if let Err(e) = w {
      println!("w was err: {}!", e);
  } else {
      println!("w was ok");
  }
}
Playground

In the first check in our code, we checked if rest is Some (Option<T> values in rust are either Some(T) or None). If so, we bind it to a new variable (also called rest, there is no need to choose a new name, this newly bound variable has a smaller scope). We use the if let pattern again, to check if we have at least 2 characters at the beginning of rest:

#![allow(unused)]
fn main() {
if let Some(rest) = rest {
    if let Some(&[first, second]) = rest.get(0..2) {
}