如何在不切片的情况下解构向量?
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
转移到name
和score
。
第一个问题更难,涉及到 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 不再拥有它,我们可以用它做任何我们想做的事情。我们立即对其进行解构。 items
、name
和 score
都有独立的生命周期。
从向量中转移所有元素所有权
let items = vec![("Peter".to_string(), 180)];
for (name, score) in items
println!(" scored ", name, score);
在这里,我们使用该向量,因此在for
循环之后不再可以使用它。 name
和 score
的所有权转移到循环绑定中的变量。
克隆项目
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 推力向量?