我正在玩Vec
结构,并遇到了一些我无法理解的有趣错误和行为。考虑following code。
fn main() {
let v = vec![box 1i];
let f = v[0];
}
在防锈围栏中进行评估时,代码会产生以下错误:
<anon>:3:13: 3:17 error: cannot move out of dereference (dereference is implicit, due to indexing)
<anon>:3 let f = v[0];
^~~~
<anon>:3:9: 3:10 note: attempting to move value to here (to prevent the move, use `ref f` or `ref mut f` to capture value by reference)
<anon>:3 let f = v[0];
^
error: aborting due to previous error
playpen: application terminated with error code 101
Program ended.
我对Vec
index
方法的理解是它返回对Vec
中值的引用,因此我不了解移动或隐含的内容正在进行解除引用。
此外,当我change the f
variable to an underscore时,如下所示,不会产生任何错误!
fn main() {
let v = vec![box 1i];
let _ = v[0];
}
我希望有人可以解释我所遇到的错误,以及在将f
转换为_
时它们消失的原因。
答案 0 :(得分:2)
不知道哪个语法糖v[0]
实现了,但它试图移动值而不是获取引用。
但是如果你打电话给.index()
,它会起作用,并为你提供一个与矢量相同生命周期的参考:
fn main() {
let v = vec![box 1i];
let f = v.index(&0);
println!("{}", f);
}
第二个例子有效,因为当值被丢弃时,它不会尝试移动它。
编辑:
v[0]
的desugar是*v.index(&0)
(来自:https://github.com/rust-lang/rust/blob/fb72c4767fa423649feeb197b50385c1fa0a6fd5/src/librustc/middle/trans/expr.rs#L467)。
fn main() {
let a = vec!(1i);
let b = a[0] == *a.index(&0);
println!("{}" , b);
}
true
答案 1 :(得分:1)
在您的代码中,let f = v[0];
按值分配f(如错误消息中所述,它隐式取消引用):编译器尝试将v[0]
复制或移动到f
。 v[0]
为box
,无法复制,因此应该像这种情况一样移动:
let a = box 1i;
let b = a;
// a cannot be used anymore, it has been moved
// following line would not compile
println!("{}", a);
但是值不能通过索引从向量中移出,因为它是返回的引用。
关于_
,此代码:
fn main() {
let v = vec![box 1i];
let _ = v[0];
println!("{}", _);
}
产生此错误:
<anon>:4:20: 4:21 error: unexpected token: `_`
<anon>:4 println!("{}", _);
^
_
不是变量名,而是生锈的特殊名称,告诉您不关心该值,因此编译器不会尝试复制或移动任何内容。
答案 2 :(得分:1)
您可以通过取消引用v [0]来获得原始功能:
fn main() {
let v = vec![box 1i];
let f = &v[0]; // notice the &
println!("{}",f);
}
我不知道为什么下划线会让你的错误消失。它应该引发错误,因为仅下划线是一个无效的变量名称(我认为)。试图打印它会产生错误:
fn main() {
let v = vec![box 1i];
let _ = &v[0];
println!("{}",_);
}
输出:
<anon>:4:19: 4:20 error: unexpected token: `_`
<anon>:4 println!("{}",_);
下划线用于静音未使用的变量警告(例如,如果您定义 some_var 并且从不使用它,编译器会对您大喊大叫,但如果您定义 _some_var则会赢得#gt; t ,永远不要使用它。它还用作匹配语句中的后备,以匹配与其他路径不匹配的任何内容:
fn main() {
let v = vec![box 1i];
let f = &v[0];
match **f {
3i => println!("{}",f),
_ => println!("nothing here")
};
}
比我聪明的人应评论下划线是否是有效的变量名称。老实说,我认为编译器不应该允许它。