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")
};
}