我想知道如果向量被拥有并且之后不被使用,为什么不可能移出对向量的共享引用?
我有一些代码,如下所示:
#[derive(Debug)]
struct Item(usize);
fn main() {
let items = vec!(Item(1), Item(2), Item(3), Item(4));
let num: Item = handle_selection_and_return(items);
dbg!(num);
}
/// Item is selected here, e.g. via UI.
fn select(items: &[Item]) -> &Item {
return &items[1];
}
fn handle_selection_and_return(items: Vec<Item>) -> Item {
// Additional code that may add additional items.
// ...
// Now select the item and return it.
*select(&items)
}
这会导致以下错误:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:20:5
|
20 | *select(&items)
| ^^^^^^^^^^^^^^^ move occurs because value has type `Item`, which does not implement the `Copy` trait
|
note: if `Item` implemented `Clone`, you could clone the value
--> src/main.rs:2:1
|
2 | struct Item(usize);
| ^^^^^^^^^^^ consider implementing `Clone` for this type
...
20 | *select(&items)
| --------------- you could clone this value
For more information about this error, try `rustc --explain E0507`.
error: could not compile `playground` (bin "playground") due to 1 previous error
我不明白为什么需要在这里克隆该项目,因为之后不再使用该向量。有什么方法可以避免不必要的克隆吗?
至少有几种不同的方式来看待这个问题。
首先,语言语义视角。你本质上问的是这样的:“如果我有一个函数接受一个引用并返回一个引用,为什么当该函数的调用站点传递一个引用时,Rust 不会自动将其提升为获取并返回一个拥有的值到它拥有且即将丢弃的对象”。即使该语言可以做到这一点(见下文),那么增加的复杂性真的值得吗?具有此类隐式操作的语言很快就会很难理解:当您在文档中阅读相关内容时,每个操作本身听起来很简洁,但随后您会看到一行以某种非常精确的方式组合了其中两个或三个操作,并且它很快就会导致“我实际上不明白这段代码在做什么”。如果您创建一个
select_owned([Item]) -> Item
并使用它,那么人们会更容易理解。
其次,从内存角度:Vec 中的 Item 位于堆中,但本地
Item
位于堆栈中。当你删除Vec时,它的堆内存将被释放;如果该堆栈项目的值以某种方式神奇地“重定向”到(不再有效)堆分配的项目,您预计会发生什么情况?一旦 Vec 被丢弃,它的 Items 就不再存在。如果您想在该生命周期之后继续使用它,则需要将其复制到新位置(在本例中为堆栈)。您的两个标准选项是 .clone()
或复制,后者是您想要做的事情 - 但这要求类型实现 Copy
,显然它没有。