heapOverflow
heapOverflow

Reputation: 1275

How can I destructure a vector of &str?

My situation:

let mut str_vect = Vec::new();
str_vect.push("a");
str_vect.push("b");
str_vect.push("c");
let [a, bc @ ..] = str_vect[..];
println!("{:?} {:?}", a, bc);

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8e4c47b024e0c871676626069ec07d52

I get this error:

the size for values of type [&str] cannot be known at compilation time

Why is that? Can I somehow destructure of Vec of &str?

Upvotes: 2

Views: 970

Answers (3)

Netwave
Netwave

Reputation: 42688

Another option would be to use iterators:

fn main() {
   let mut str_vect = Vec::new();
   str_vect.push("a");
   str_vect.push("b");
   str_vect.push("c");
   let (a, bc) = {
        let mut it = str_vect.into_iter();
        (it.next(), it)
   };
   println!("{:?} {:?}", a.unwrap(), bc.collect::<Vec<_>>());
}

Playground

Of course this makes you have to check and/or collect to whatever you need later on. You could just use the iterator if you need. Notice I used into_iter which consumes the vector, but you could use iter to just work with references instead too.

Upvotes: 1

prog-fh
prog-fh

Reputation: 16850

Another solution, which is definitely not destructuring, but which is easier to read in my opinion because the name expresses the intention, would rely on split_first().

    let (a, bc) = str_vect.split_first().unwrap();

Of course, some appropriate error handling should be considered instead of unwrap.

And yes, the other answer is far better because it explains in details the origin of the reported error (I just upvoted it ;^).

Upvotes: 5

Chayim Friedman
Chayim Friedman

Reputation: 70950

Just add a &: v[..] is a DST ([T], not &[T]). This is fine as long as we only access individual elements, but for rest patterns (..), that produce a slice - they will have to produce [T], too, and that is unsized. If you match against &[T], on the other hand, the rest pattern also gives &[T] (another possibility is to use ref - ref bc @ .., but I would not recommend that).

let [a, bc @ ..] = &str_vect[..];

Playground.

However, this fails with:

error[E0005]: refutable pattern in local binding: `&[]` not covered
 --> src/main.rs:6:8
  |
6 |    let [a, bc @ ..] = &str_vect[..];
  |        ^^^^^^^^^^^^ pattern `&[]` not covered
  |
  = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
  = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
  = note: the matched value is of type `&[&str]`
help: you might want to use `if let` to ignore the variant that isn't matched
  |
6 |    let (a, bc) = if let [a, bc @ ..] = &str_vect[..] { (a, bc) } else { todo!() };
  |    ++++++++++++++++                                  ++++++++++++++++++++++++++++

That is because any slice pattern except [..] is refutable - that is, may fail. What if str_vect (theoretically) has zero elements? We cannot bind the first element in that case! You need if let or match to handle that case.

Upvotes: 6

Related Questions