引用如何在绑定表达式的模式中工作?

Aks*_*aik 0 iterator reference rust

我在 Rust 书中遇到了下面的例子。

for &item in list.iter() {
    if item > largest {
        largest = item;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想这意味着list.iter()返回对列表中元素的引用,&item但是在将其与最大数字进行比较时,为什么我们不使用*item&item另外,当我将第一行中的to更改为时,编译器item强制我在第二行和第三行中使用。*item

我在网上看到了另一个例子。

(0..).map(|x| x * x)
    .take_while(|&x| x <= limit)
    .filter(|x| is_even(*x))
Run Code Online (Sandbox Code Playgroud)

这里的闭包take_while接受&x但直接使用x,但闭包filter接受x而不引用但传递*xis_even

那么这在 Rust 中是如何工作的呢?

Luk*_*odt 5

您在这里看到的称为解构。通过此功能,您可以使用图案来分解结构。

您可能已经看到过类似的内容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;
Run Code Online (Sandbox Code Playgroud)

这具有反直觉的效果,即在模式中添加的越多,变量的类型就越&&少。但它在解构的上下文中确实有意义:当您已经在模式中提到结构时,该结构将不再位于绑定变量中。

(值得注意的是,这种“解构引用”仅适用于 的裁判类型Copy。否则您将收到“无法移出借用的内容”错误。)


for现在这与你的循环和闭包有什么关系?事实证明:模式无处不在。forfor 循环中和之间的槽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]) {}
Run Code Online (Sandbox Code Playgroud)

我想这意味着list.iter()返回对列表中元素的引用

确切地。

... 因此&item

“因此”在这里不正确。此代码的作者不想使用对该项目的引用,而是使用实际值。因此他们&在模式中添加了 来解构引用。

但在与最大数字进行比较时,为什么我们不使用*item

是的,因为引用已经被解构模式删除了。

&item另外,当我将第一行中的to更改为时,编译器item强制我在第二行和第三行中使用。*item

是的,因为现在模式不再破坏引用,所以item再次引用。这是所有这一切的基本要点:大多数时候,您可以通过添加 a 来删除模式中的引用& ,也可以在使用变量时通过添加 a 来删除引用*

这里的闭包take_while接受&x但直接使用x,但闭包filter接受x而不引用但传递*xis_even

现在应该很清楚为什么会这样了吧?闭take_while包通过模式中的解构来删除引用,而filter闭包则通过标准解引用来删除引用。


您可以在本书的这一章中阅读有关所有这些内容的更多信息。