Using a match with an option element from a vector

I'm trying to only print the first element of the vector if it contains something:

let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
match optional_integers_vec[0].unwrap() {
  Err(e) => println!("Nothing in the first element currently"),
  Ok(_) => println!("Vec contains in first element {}",optional_integers_vec[0].unwrap() ),
}

This produces the following error:
Err(e) ^^^^^^ expected i8, found enum Result
Ok(_) ^^^^^ expected i8, found enum Result

Option::unwrap() is primarily useful when you're certain that the value is Some, since it's an assertion that throws a panic on failure. To test whether or not the value is Some, you can match on it directly (Rust Playground):

  let optional_integers_vec: Vec<Option<i8>> = vec![Some(42)];
  match optional_integers_vec[0] {
      None => println!("Nothing in the first element currently"),
      Some(v) => println!("Vec contains in first element {v}"),
  }

(Note that this will panic if optional_integers_vec is empty.)

1 Like

You could do

optional_integers_vec.iter().nth(0).map(|maybe_first_element| {
  match maybe_first_element {
    Some(first_element) => {
      println!("first element was {first_element}")
    }
    None => println!("first element was None")
  }
}

That's better expressed as the_vec.first().

4 Likes

I would do something like this:

    let my_vec = vec![Some(1)];
    if let Some(num) = my_vec[0] {
        println!("{}", num);
    }

If you want a reference of the value inside the option just do this:

    let my_vec = vec![Some(1)];
    if let Some(num) = my_vec[0].as_ref() {
        println!("{}", num);
    }

But as a safety line, always check if the vector got a value or not before doing the above code or else your programe will panic!!

Note that this won't work for non-Copy types.

1 Like

then just get a reference of it like the code below it

How about this? (link to the playground)

let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
match &*optional_integers_vec {
  [] => println!("empty Vec"), 
  [None, ..] => println!("Nothing in the first element currently"),
  [Some(elt), ..] => println!("Vec contains in first element {elt}" ),
} 

This doesn't panic, clearly enumerates the possible cases, and doesn't require manually digging into the Vec and its elements since pattern matching does it for you.

5 Likes

Thanks, appreciate the advice on unwrap

Thanks I appreciate your replies, I'm learning new things every day

Thanks jjpe, I liked your solution the best.

I ended up putting it into a function like this, NB the compiler didn't like match veccy and suggested match veccy[..]:

fn first_el_print(veccy : &Vec<Option<i8>>){
  match veccy[..]{

    [] => println!("Vec is empty"),
    [None, ..] => println!("Nothing in first element"),
    [Some(elem), ..] => println!("Vec contains something in 1st element which is {}",elem),

  }
}

That gets called like this:

let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
first_el_print(&optional_integers_vec);

I'm pretty new to Rust, I would like to ask about where you used the address and the dereference together &*, I'm confused by that and haven't seen it before, is it a way of making certain that you get the address of the actual datastructure rather than say of its pointer?:

match &*optional_integers_vec

That's why you needed [..]. In case of Vec, these are two ways to convert it into borrowed slice: one is using Deref coercion (&*v first converts Vec<T> to [T] via dereference and then give back the &[T]), another - Index operator.

3 Likes

Thanks Cerber-Ursi, I appreciate the explanation.

Note that you shouldn't accept a &Vec as a function parameter. It is useless (an immutable vector doesn't have more API than a slice), and can actually hurt performance, because it forces the caller to have an actual owned vector, instead of just a slice. So if someone has, say, a stack-allocated array, which would deref to a slice just fine, you will force them to copy the array into a heap-allocated vector. Just accept a slice instead.

1 Like