这个问题在这里已有答案:
我在Rust书中看到了下面的例子。
for &item in list.iter() {
if item > largest {
largest = item;
}
}
我想这意味着list.iter()
返回对列表中元素的引用,因此&item
但是在将它与最大数字进行比较时,为什么我们不使用*item
?此外,当我在第一行将&item
更改为item
时,我被编译器强制在第2行和第3行使用*item
。
我在网上看到了另一个例子。
(0..).map(|x| x * x)
.take_while(|&x| x <= limit)
.filter(|x| is_even(*x))
在这里take_while
的封闭接受&x
但直接使用x
但filter
的封闭在没有参考的情况下接受x
但是将*x
传递给is_even
。
那么这在Rust中是如何工作的?
你在这里看到的是所谓的解构。这是一个可以拆分带有图案的结构的功能。
你可能已经看过像let (a, b) = returns_a_tuple();
这样的东西了。在这里,元组被解构。您还可以解构引用:
// The comments at the end of the line tell you the type of the variable
let i = 3; // : i32
let ref_i = &i; // : &i32
let ref_ref_i = &ref_i; // : &&i32
let &x = ref_i; // : i32
let &y = ref_ref_i; // : &i32
let &&z = ref_ref_i; // : i32
// All of these error because we try to destructure more layers of references
// than there are.
let &a = i;
let &&b = ref_i;
let &&&c = ref_ref_i;
这具有反直觉效果,即您在模式中添加的&
越多,变量类型的&
就越少。但它在解构的上下文中确实有意义:当你已经提到模式中的结构时,结构将不再存在于绑定变量中。
(值得注意的是,这种“解构引用”仅适用于Copy
的裁判类型。否则你将获得“无法摆脱借来的内容”的错误。)
那你的for
循环和闭包有什么关系呢?事实证明:模式无处不在。 for循环中for
和in
之间的槽是一个模式,函数和闭包的参数也是模式!这有效:
// Destructuring a tuple in the for loop pattern
let v = vec![3];
for (i, elem) in v.iter().enumerate() {}
// Destructuring an array in the function argument (works the same for closures)
fn foo([x, y, z]: [f32; 3]) {}
我想这意味着
list.iter()
返回对列表中元素的引用
究竟。
...因此
&item
“因此”在这里不正确。此代码的作者不希望使用对项目的引用,而是使用真正的值。所以他们在模式中添加了&
来消除参考。
但是,与最大数字相比,为什么我们不使用
*item
?
是的,因为已经通过解构模式删除了引用。
此外,当我在第一行将
&item
更改为item
时,我被编译器强制在第2行和第3行使用*item
。
是的,因为现在模式不再破坏参考,所以item
再次参考。这是所有这一切的基本要点:大多数情况下,您可以通过添加&
删除模式中的引用,或者您可以通过添加*
来使用变量时删除引用。
在这里
take_while
的封闭接受&x
但直接使用x
但filter
的封闭在没有参考的情况下接受x
但是将*x
传递给is_even
。
现在应该清楚为什么会这样,对吧? take_while
闭包通过模式中的解构来移除引用,而filter
闭包通过标准解除引用来完成它。
你可以在this chapter of the book上阅读更多关于这一切的信息。