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

Posted

技术标签:

【中文标题】如何在不切片的情况下解构向量?【英文标题】:How do I destructure a vector without taking a slice? 【发布时间】:2015-06-01 17:16:16 【问题描述】:

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

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)>`

【问题讨论】:

相关问题:***.com/questions/28851989/… 【参考方案1】:

你同时问了两个不相交的问题:

    如何才能移出向量? 如何解构项目?

第二个很简单:

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

在这里,我们获取对第一个项目的引用,然后是对名称和分数的引用。由于向量可能没有任何项目,它返回一个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);

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

【讨论】:

谢谢!令人遗憾的是,编译器无法像解构 item 元组时那样支持将项目移出向量。 @PeterHorne 我不确定你的意思。如果foo = vec[0] 将所有权从向量转移到变量foo 中,您希望vec[0] 表示所有权转移之后? 与在(a, b) = items 之后尝试访问items 相同——错误(使用部分移动的值) @PeterHorne:不过,你大大高估了目前的 Rust 类型系统。部分移动仅适用于未实现 Drop 特征的结构(请参阅 is.gd/tRTWDR => 无法移出类型 Person,它定义了 Drop 特征),因为那么编译器就无法知道Drop trait 将依赖什么。 如果您确实需要使用.remove(0),将数据结构更改为VecDeque 并使用.pop_front() 将获得更好的性能,并且不会出现恐慌。【参考方案2】:

你不能这样做,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

【讨论】:

即使可以,您也可能不应该也不想直接弄乱指针。 当然,只是演示如何匹配一个 Vec

以上是关于如何在不切片的情况下解构向量?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不更改其参考的情况下将更改应用于张量/向量的元素?

如何在不使用向量的情况下将数组传递给函数?

如何在不知道宽度的情况下将元素存储在二维向量中?

如何在不隐式调用“复制”的情况下初始化 CUDA 推力向量?

R:如何在不使用循环的情况下按唯一向量顺序查找所有重复向量值的索引?

如何在不重复预定义三元组中的特定元素的情况下随机化向量?