Vec: "pop" an item conditionally

I would like to "pop" an item from a vector under a certain condition. Otherwise I would like to create a default value:

// pops or gets a new item
let mut items = vec![vec![0, 1, 2], vec![0, 1, 2]];
let item = match items.pop() {
    Some(item) if item.len() < 3 => item,
    _ => def_value,
};

// pushes the previous item
items.push(item);

but the compiler throws the following error:

error[E0008]: cannot bind by-move into a pattern guard
   |
28 |             Some(item) if item.len() < 3 => item,
   |                  ^^^^ moves value into pattern guard

Is that possible?

That code always pops the last item before checking if it matches the criteria. You could do:

let item = match items.last() {
    Some(item) if item.len() < 3 => items.pop().unwrap(),
    _ => def_value,
};
5 Likes

Equivalent of your code (which is different from your description) would be:

items.pop().filter(|item| item.len()<3).unwrap_or(def_value);
2 Likes