今天的Rust之谜来自The Rust Programming Language,第一版的第4.9节 . 引用和借用的示例有这个例子:
fn main() {
fn sum_vec(v: &Vec<i32>) -> i32 {
return v.iter().fold(0, |a, &b| a + b);
}
fn foo(v1: &Vec<i32>) -> i32 {
sum_vec(v1);
}
let v1 = vec![1, 2, 3];
let answer = foo(&v1);
println!("{}", answer);
}
这看似合理 . 它打印"6",如果 sum_vec
的 v
是C引用,这就是你所期望的;它只是一个内存位置的名称,我们在 main()
中定义了向量 v1
.
然后我用这个替换了 sum_vec
的主体:
fn sum_vec(v: &Vec<i32>) -> i32 {
return (*v).iter().fold(0, |a, &b| a + b);
}
它按预期编译和工作 . 好吧,那不是......完全疯了 . 编译器试图让我的生活更轻松,我明白了 . 令人困惑的是,我必须记住这些语言的特定时态,但并非完全疯狂 . 然后我尝试了:
fn sum_vec(v: &Vec<i32>) -> i32 {
return (**v).iter().fold(0, |a, &b| a + b);
}
它仍然有效!我勒个去?
fn sum_vec(v: &Vec<i32>) -> i32 {
return (***v).iter().fold(0, |a, &b| a + b);
}
type [i32] cannot be dereferenced
. 哦,感谢上帝,这是有道理的 . 但我原本预计会有两次迭代!
Rust中的引用不是C "names for another place in memory,"但它们是什么?它们也不是指针,关于它们的规则似乎要么是深奥的,要么是高度特殊的 . 发生了什么,这样一个引用,一个指针和一个指向指针的指针在这里同样运作良好?
1 回答
规则不是临时的,也不是真正的深奥 . 检查
v
的类型,它有各种解除引用:你会得到:
v
- >&std::vec::Vec<i32>
*v
- >std::vec::Vec<i32>
**v
- >[i32]
您已经理解的第一个解引用 . 第二个取消引用归功于Deref特征 .
Vec<T>
对[T]
的引用 .执行方法查找时,there's a straight-forward set of rules:
如果类型具有方法,请使用它并退出查找 .
如果对该类型的引用具有该方法,请使用它并退出查找 .
如果可以取消引用类型,请执行此操作,然后返回步骤1 .
否则查找失败 .
它们绝对是记忆中一个地方的名字 . 实际上,它们会编译成您知道的相同C / C指针 .