在以下情况下出现令人困惑的编译错误:
这是一个代码示例:
fn main()
{
let mut v = Vec::<(int,String)>::new();
v.push((3, String::new()));
let u = v[0].val0();
}
产生以下错误:
error: cannot move out of dereference (dereference is implicit, due to indexing)
我认为我对所有权,借用,参考和生命周期有一个合理的理解,但我仍然没有得到这个错误。为什么会这样?
更新
感谢Vladimir和Levans的回答。
弗拉基米尔,我会按照建议使用元组索引语法,但我最感兴趣的是“为什么”。为什么不能这么简单的工作?
正如Levans所说,val0的定义是:
fn val0(self) -> A
我设法进一步简化了我的例子:
fn main()
{
let t : (int, String) = (3, String::new());
let u = t.val0();
let v = t.val1();
}
这给我带来了以下错误:
main.rs:8:13: 8:14 error: use of moved value: `t`
main.rs:8 let v = t.val1();
main.rs:7:13: 7:14 note: `t` moved here because it has type `(int,collections::string::String)`, which is non-copyable (perhaps you meant to use clone()?)
main.rs:7 let u = t.val0();
这就是我要找的东西。我缺少的是复杂类型无法按值复制。因此,它们被移动到被调用的函数的范围。
请注意,以下内容确实有效,因为(int,int)不是复杂类型:
fn main()
{
let t : (int, int) = (3, 4);
let u = t.val0();
let v = t.val1();
}
我仍然认为在原始示例(使用Vec)的错误消息中包含更多信息会非常有用。
答案 0 :(得分:4)
使用最近的Rust编译器,您不需要valX()
/ refX()
方法,您可以使用元组索引语法。我真的很惊讶他们没有被弃用(可能是因为元组索引仍然在功能门之后)。元组索引如下所示:
#![feature(tuple_indexing)]
fn main() {
let mut v = Vec::<(int,String)>::new();
v.push((3, String::new()));
let u = v[0].0; // use 1st (with zero-based indices) field of a tuple
println!("{}", u);
}
幸运的是,这个程序可以正常工作,因为访问元组字段就像访问常规结构中的字段一样 - 它不需要取得整个结构的所有权,它支持部分移动。在这种特殊情况下,第一个字段类型是可隐式复制的,因此您只需访问它就可以复制它。
答案 1 :(得分:3)
val0()
的原型是:
fn val0(self) -> A
如你所见,它消耗元组来解开第一个值。因此,当你在v[0]
上调用它时,它会有效地尝试将元组移动到val0()
的范围内,这是禁止的,因为元组由你的Vec拥有。
您可能想要使用ref0
,它会为您提供对第一项的引用,而不会消耗元组:
fn ref0(&'a self) -> &'a A