循环变量前的`&` 的目的是什么?

Muh*_*fil 10 reference pattern-matching destructuring ampersand rust

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

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));
}
Run Code Online (Sandbox Code Playgroud)

操场

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

fn main() {
    let mut hey: i32 = 32;
    let x: i32 = 2;
    hey = &&x;
}
Run Code Online (Sandbox Code Playgroud)

它说:

fn main() {
    let mut hey: i32 = 32;
    let x: i32 = 2;
    hey = &&x;
}
Run Code Online (Sandbox Code Playgroud)

ruo*_*ola 14

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

但是,当您使用 时for &i in list,您并没有取消引用任何内容,而是使用模式匹配来显式地解构引用,这将使其i成为类型i32

请参阅 Rust 文档,了解 for 循环循环变量是一种模式以及我们在此处使用的参考模式。另请参阅有关解构指针的 Rust By Example 章节。

 

解决此问题的另一种方法是保持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
}
Run Code Online (Sandbox Code Playgroud)

 


fn main() {
    let mut hey: i32 = 32;
    let x: i32 = 2;
    hey = &&x;
}
Run Code Online (Sandbox Code Playgroud)

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


Luk*_*odt 12

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

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

let (a, b) = ('x', true);
Run Code Online (Sandbox Code Playgroud)

在右手边有一个类型的值(char, bool)(一个元组)。该值绑定到左侧模式 ( (a, b))。如已经有一个“结构”中的图案(即,元组)中所定义,该结构是除去,aUNDb结合到元组的元素。因此,aischar的类型和bis的类型bool

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

let [x] = [true];
Run Code Online (Sandbox Code Playgroud)

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

不出所料,这也适用于参考!

let foo = 0u32;
let r = &foo;
let &c = &foo;
Run Code Online (Sandbox Code Playgroud)

这里,foo有类型u32,因此,表达式&foo有类型&u32。的类型r也是&u32,因为它是一个简单的let绑定。然而的类型cu32!那是因为“引用已被模式解构/删除”。

一个常见的误解是模式中的语法与表达式中的相同语法具有完全相反的效果!如果您有一个a类型为 的变量[T; 1],那么表达式[a]的类型为[[T; 1]; 1]? 它增加了东西。但是,如果您绑定a到 pattern [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`
Run Code Online (Sandbox Code Playgroud)

这也解释了你的问题:

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

fn main() {
   let mut hey:i32 = 32;
   let x:i32 = 2;
   hey = &&x;
}
Run Code Online (Sandbox Code Playgroud)

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


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


相关问题