循环变量前加“&”的目的是什么?

What is the purpose of `&` before the loop variable?

代码&i in list&的作用是什么?如果我删除 &,它会在 largest = i 中产生错误,因为它们的类型不匹配(其中 i&32ii32).但是&i如何将i转换成i32呢?

fn largest(list: &[i32]) -> i32 {
    println!("{:?}", list);
    let mut largest = list[0];
    for &i in list {
        if i > largest {
            largest = i;
        }
    }
    largest
}

fn main() {
    let hey = vec![1, 3, 2, 6, 90, 67, 788, 12, 34, 54, 32];
    println!("The largest number is: {}", largest(&hey));
}

Playground

它似乎以某种方式取消引用,但为什么在下面的代码中它不起作用?

fn main() {
    let mut hey: i32 = 32;
    let x: i32 = 2;
    hey = &&x;
}

它说:

4 |     hey = &&x;
  |           ^^^ expected i32, found &&i32
  |
  = note: expected type `i32`
             found type `&&i32`

所以通常当你使用 for i in list 时,循环变量 i 的类型是 &i32.

但是当你使用 for &i in list 时,你并不是 取消引用 任何东西,而是 你正在使用模式匹配来显式 destructure 引用 并且这将使 i 只是类型 i32.

查看有关 for-loop 循环变量的 Rust 文档 being a pattern and the reference pattern that we are using here. See also the Rust By Example chapter on destructuring pointers

解决此问题的另一种方法是保持 i 不变,然后将 i 与对 largest 的引用进行比较,然后取消引用 i ] 在分配给 largest 之前:

fn largest(list: &[i32]) -> i32 {
    println!("{:?}", list);
    let mut largest = list[0];
    for i in list {
        if i > &largest {
            largest = *i;
        }
    }
    largest
}


fn main() {
    let mut hey: i32 = 32;
    let x: i32 = 2;
    hey = &&x;
}

这根本行不通,因为在这里您要将 hey(即 i32)分配给对 i32 的引用的引用。这与循环变量情况下的模式匹配和解构完全无关。

这是解构的效果。我不会在这里完全描述该功能,但简而言之:

在许多语法上下文中(let 绑定,for 循环,函数参数,...),Rust 需要一个“模式”。这个模式可以是一个简单的变量名,但也可以包含一些“解构元素”,比如&。然后 Rust 会为这个模式绑定一个值。一个简单的例子是这样的:

let (a, b) = ('x', true);

右侧有一个 (char, bool) 类型的值(一个元组)。此值绑定到左手模式 ((a, b))。由于模式中已经定义了一个“结构”(特别是元组),该结构被删除并且 ab 绑定到元组的元素。因此,a 的类型是 charb 的类型是 bool.

这适用于几个结构,包括数组:

let [x] = [true];

同样,在右侧我们有一个 [bool; 1] 类型的值(一个数组),在左侧我们有一个数组形式的模式。单个数组元素绑定x,意思是x的类型是bool不是 [bool; 1]!

毫不奇怪,这也适用于参考!

let foo = 0u32;
let r = &foo;
let &c = &foo;

此处,foo 的类型为 u32,因此,表达式 &foo 的类型为 &u32r 的类型也是 &u32,因为它是一个简单的 let 绑定。然而 c 的类型是 u32!那是因为模式的“引用是 destructured/removed”。

一个常见的误解是,模式中的语法与相同语法在表达式中的效果完全相反! 如果您有一个 a 类型的变量[T; 1],那么表达式 [a] 的类型是 [[T; 1]; 1] → 它 添加 东西。但是,如果将 a 绑定到模式 [c],则 y 具有类型 T → 它 删除 东西。

let a = [true];    // type of `a`: `[bool; 1]`
let b = [a];       // type of `b`: `[[bool; 1]; 1]`
let [c] = a;       // type of `c`: `bool`

这也解释了你的问题:

It seems like it is somehow dereferencing, but then why in the below code, it is not working?

fn main() {
   let mut hey:i32 = 32;
   let x:i32 = 2;
   hey = &&x;
}

因为您在表达式端使用了 &,它 添加了 一层引用。


最后关于你的循环:当迭代一个切片时(就像你在这里所做的那样),迭代器产生对切片元素的引用。所以在 for i in list {} 的情况下,i 的类型是 &i32。但是赋值 largest = i; 需要在右侧有一个 i32。您可以通过两种方式实现此目的:通过取消引用运算符 *(即 largest = *i;)取消引用 i 或在循环模式中解构引用(即 for &i in list {})。


相关问题: