如何在不切片的情况下解构向量?

How do I destructure a vector without taking a slice?

我可以通过获取一个向量的切片并引用元组中的项目来解构一个元组向量:

let items = vec![("Peter".to_string(), 180)];

if let [(ref name, ref age)] = items.as_slice() {
    println!("{} scored {}", name, age);
};

如何直接解构向量,将项目移出元组。像这样:

let items = vec![("Peter".to_string(), 180)];

if let [(name, age)] = items {
    println!("{} scored {}", name, age);
};

编译以上结果报错:

error[E0529]: expected an array or slice, found `std::vec::Vec<(std::string::String, {integer})>`
 --> src/main.rs:4:12
  |
4 |     if let [(name, age)] = items {
  |            ^^^^^^^^^^^^^ pattern cannot match with input type `std::vec::Vec<(std::string::String, {integer})>`

你不能这样做,the definition of Vec in std

pub struct Vec<T> {
    ptr: Unique<T>,
    len: usize,
    cap: usize,
}

所以不能直接匹配,只能:

match xs {
    Vec { ptr: x, .. } => {...}
} 

但是

error: field `ptr` of struct `collections::vec::Vec` is private

您同时问了两个不相干的问题:

  1. 我怎样才能移出向量?
  2. 如何解构一个项目?

第二个很简单:

let item = ("Peter".to_string(), 180);
let (name, score) = item;

您不需要 if let 语法,因为这种模式匹配不可能失败。当然,你不能在解构后使用 item 因为你已经 将所有权 item 转移到 namescore .

第一个问题比较难,涉及到 Rust 的核心部分。如果您将所有权从向量中移出,那么向量在中处​​于什么状态?在 C 语言中,您会在向量中放置一些未定义的内存块,等待分解您的程序。假设您在那个字符串上调用了 free,那么当您在向量中使用指向同一字符串的东西时会发生什么?

有几种方法可以解决...

向量继续拥有项目

let items = vec![("Peter".to_string(), 180)];

if let Some((name, score)) = items.first() {
    println!("{} scored {}", name, score);
}

在这里,我们获取 第一项的引用,然后是对名称和分数的引用。由于向量可能没有任何项目,它 returns 和 Option,所以我们使用 if let。编译器不会让我们使用这些项目超过矢量寿命。

从矢量转移一个元素的所有权

let mut items = vec![("Peter".to_string(), 180)];

let (name, score) = items.remove(0); // Potential panic!
println!("{} scored {}", name, score);

在这里,我们 remove 数组中的第一项。 vector 不再拥有它,我们可以用它做任何我们想做的事。我们立即解构它。 itemsnamescore 都有独立的生命周期。

转移向量中的所有元素所有权

let items = vec![("Peter".to_string(), 180)];

for (name, score) in items {
    println!("{} scored {}", name, score);
}

在这里,我们消耗 向量,因此在for 循环后它不再可用。 namescore 的所有权转移到循环绑定中的变量。

克隆项目

let items = vec![("Peter".to_string(), 180)];

let (name, score) = items[0].clone(); // Potential panic!
println!("{} scored {}", name, score);

在这里,我们制作向量中项目的 版本。我们拥有新项目,向量拥有原始项目。