Rasmus Edvardsen
Rasmus Edvardsen

Reputation: 169

Is is possible to deconstruct a vector?

I am toying around with Rust, and am trying to take in some input, and then splitting it by white space in to a vector of strings.

I then want to destructure these inputs again in to separate values. What I have so far is this:

use std::io;

fn main() {
    println!("___Calculator___");

    let mut buffer = String::new();
    
    println!("What would you like to calculate?");

    io::stdin()
        .read_line(&mut buffer)
        .unwrap();
    
    let elements = buffer
        .split_whitespace()
        .collect::<Vec<&str>>();

    let [first, second, third] = elements[0..2];
}

Again, I know I could just read input 3 times, but I want to see how I can do different things with the language.

Edit

Here's the error from cargo run:

   Compiling calculator v0.1.0 (E:\code\rust\calculator)
error[E0005]: refutable pattern in local binding: `[]`, `[_]`, `[_, _]` and 1 more not covered
  --> src\main.rs:18:9
   |
18 |     let [first, second, third] = elements[0..2];
   |         ^^^^^^^^^^^^^^^^^^^^^^ patterns `[]`, `[_]`, `[_, _]` and 1 more 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 variants that aren't matched
   |
18 |     let (first, second, third) = if let [first, second, third] = elements[0..2] { (first, second, third) } else { todo!() };
   |     +++++++++++++++++++++++++++++++                                             +++++++++++++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0005`.
error: could not compile `calculator` due to previous error

Thanks

Upvotes: 0

Views: 1142

Answers (2)

Silvio Mayolo
Silvio Mayolo

Reputation: 70267

Rust doesn't understand that elements[0..2] is always going to be three elements. In fact, it potentially won't be, if the user enters fewer than three words. So you need to handle that case.

if let [first, second, third] = &elements[0..2] {
  ...
} else {
  println!("Enter three words plz :(");
}

EDIT: From a comment on the question, you also want elements[0..3]. Ranges are half-open in Rust.

Upvotes: 3

Chayim Friedman
Chayim Friedman

Reputation: 70950

The compiler is telling you what the problem is, and even suggests a fix:

error[E0005]: refutable pattern in local binding: `[]`, `[_]`, `[_, _]` and 1 more not covered
  --> src/main.rs:18:9
   |
18 |     let [first, second, third] = elements[0..2];
   |         ^^^^^^^^^^^^^^^^^^^^^^ patterns `[]`, `[_]`, `[_, _]` and 1 more 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 variants that aren't matched
   |
18 |     let (first, second, third) = if let [first, second, third] = elements[0..2] { (first, second, third) } else { todo!() };
   |     +++++++++++++++++++++++++++++++                                             +++++++++++++++++++++++++++++++++++++++++++

Patterns in variable declarations are required to be irrefutable, i.e. always succeed. What if the vector has less than three elements? You have to use match or if let to cover that possibility.

Upvotes: 0

Related Questions