I have a reference to a Vec
and I want to extract a reference to exactly one element from it, and panic if there are any more elements or zero. The equivalent if I had an array would be:
let [x] = list;
but Vec
s are dynamically sized, so that won't work here. I can think of one way to do it with a reference to a Vec
, and a couple more that require ownership, but I'm wondering if there's a shorter and simpler way.
assert!
and indexingassert_eq!(list.len(), 1);
let x = &list[0];
try_into()
let [x]: [i32; 1] = list.try_into().unwrap();
assert!
and pop
assert_eq!(list.len(), 1);
let x = list.pop();
So, is there a shorter and clearer way?
You can use a slice pattern combined with let else
:
let v = vec![1u32];
let &[x] = v.as_slice() else {
panic!("expected single element"); // or return, break, etc.
};
assert_eq!(x, 1);
It's not necessarily shorter than your options, but it's clear and reasonably concise, doesn't require ownership or mutation, and can be nicely generalized to more than one element to extract.
If instead of panicking you want to check the element count and extract x
if it's the only element, you can use if let
:
if let &[x] = v.as_slice() {
// ... use x ...
}
EDIT
This answer originally suggested the more verbose match
syntax, which was mandatory before let else
was introduced in Rust 1.65. It's still useful if you're contributing to a project that supports older compilers, or if you find let else
unpalatable:
let x = match v.as_slice() {
&[x] => x,
_ => panic!("expected single element"), // or return, break, etc.
};