Home > Back-end >  How to destructure n items from vec in to variables in rust
How to destructure n items from vec in to variables in rust

Time:12-06

In javascript, I can destructure an array in the following way:

const [first, second, ...rest] = myArray

Is there a similar way to achieve this in rust?

If I only want one element, it's easy. I can do:

let first = my_vec[0]

or if I make an array from a string and only want to split i once, in to two parts I can do that and get a tuple with:

let (first, second) = my_string.split_once("\n").unwrap(); (if I only need to split the array in to two parts)

But what about the more general destructuring pattern where I can ignore parts of the array and have a few variables defined and ready to go?

I'm expecting it to look something like this:

let [first, second, ...] = my_vec;

or

let [first, ..middle, second_last, last] = my_vec;

P.S forget about the unwrap-part. I know I should handle the error, but that's not the point here.

I tried using a match expression, which didn't work. It expects the array to be of length 2.


    let [first, second] = match my_vec[..] {
        [first, second] => [first, second],
        v => v,
      
    };

I complains about v and says: `match` arms have incompatible types expected array `[&str; 2]`, found slice `[&str]. That makes sense, so is there a way to achieve this?

CodePudding user response:

In Rust, you can destructure a Vec (a vector data type) by using a match statement with a tuple pattern. Here is an example of how to destructure n items from a Vec into variables:

let vec = vec![1, 2, 3, 4, 5];

match vec.as_slice() {
    // Destructure the first `n` items from the vector
    [a, b, c, .., rest] => {
        // a, b, and c will contain the first 3 items from the vector
        // rest will contain the remaining items from the vector
        println!("a = {}", a);
        println!("b = {}", b);
        println!("c = {}", c);
        println!("rest = {:?}", rest);
    }
    _ => {
        // Handle the case where there are less than 3 items in the vector
        println!("The vector does not have enough items");
    }
}

In this code, the match statement uses a tuple pattern to destructure the first 3 items from the vector and assign them to the variables a, b, and c, respectively. The remaining items are assigned to the rest variable.

Keep in mind that this code uses the as_slice method to convert the Vec to a slice, which allows us to use the tuple pattern in the match statement. If the Vec has fewer than 3 items, the _ (wildcard) pattern will be matched and the println statement in the _ branch will be executed.

You can modify this code to destructure a different number of items from the Vec by changing the tuple pattern in the match statement. For example, to destructure the first 4 items from the Vec, you could use the following pattern:

[a, b, c, d, .., rest]

You can also use the rest variable to access the remaining items in the Vec after they have been destructured. For example, you could use the following code to print all the items in the Vec:

match vec.as_slice() {
    [a, b, c, .., rest] => {
        println!("a = {}", a);
        println!("b = {}", b);
        println!("c = {}", c);
        for item in rest {
            println!("{}", item);
        }
    }
    _ => {
        // Handle the case where there are less than 3 items in the vector
        println!("The vector does not have enough items");
    }
}

CodePudding user response:

The v => v match arm in OP's code has an incompatible type with the first match arm. When using match, the resulting types of all match arms must be compatible, but we can make use panic! to make the branch divergent instead.

fn main() {
    let my_vec = vec!["first", "second"];
    let [first, second] = match my_vec[..] {
        [first, second] => [first, second],
        _ => panic!("match failed"),
    };
}

CodePudding user response:

Ok, I found a way to destructure arbitrary entries from an array (vec) in rust. It's not perfect. If index is out of bounce, the program will panic.

let [first, second, fifth] = { [my_vec[0], my_vec[1], my_vec[5]] };

I also found that you can do string slices, but as far as I see I can only take ranges, not pick and chose. At least not without it being verbose and complicated.

let [first, second, third]: &[_; 3] = my_vec[..3].try_into().unwrap();

CodePudding user response:

You can use match with following pattern.

[first, middle @ .., last]

to bind the first and last values, and store the rest of them in a single array(middle).

ie,

fn main() {
    let my_vec = vec![1, 2, 3, 4, 5];
    match my_vec.as_slice() {
        [first, middle @ .., last] => {
            println!("{:?}, {:?}, {:?}", first, middle, last)
        },
        _ => {

        }
    }
}

This will result in following output.

"first", ["second"], "third"

You can also use if let syntax.

fn main() {
    let my_vec = vec!["first", "second"];
    if let [first, middle @ .., last] = my_vec.as_slice() {
        println!("{:?} {:?} {:?}", first, middle, last);
    } else {
        panic!("The slice is either empty or contains only single element")
    };
}
  • Related