【问题标题】:What is & doing in a rust for in loop? [duplicate]在循环中生锈的 & 在做什么? [复制]
【发布时间】:2021-09-29 06:35:59
【问题描述】:

试图了解& 如何在生锈的for..in 循环中工作... 例如,假设我们有一个简单的东西,比如查找最大值函数,它获取i32 的切片并返回最大值。

fn largest(list: &[i32]) -> i32 {
    let mut largest = list[0];

    for item in list {
        if *item > largest {
            largest = *item;
        }
    }

    largest
}

在上面给出的场景中,item 将是一个&i32,这对我来说很有意义。我们借用了i32 的切片,因此item 也将是切片中单个项目的引用。在这一点上,我们可以用* 取消引用item 的值,这就是我假设基于指针的语言的工作方式。

但是现在如果我们在下面稍微改变一下......

fn largest(list: &[i32]) -> i32 {
    let mut largest = list[0];

    for &item in list {
        if item > largest {
            largest = item;
        }
    }

    largest
}

如果我们将& 放在item 前面,这会将for..in 中的item 更改为i32... 为什么?在我看来,这与我想象它的工作方式完全相反。这对我来说,“给我一个地址/参考item”......这本身就已经是一个参考。那么item 是如何被取消引用的呢?这只是生锈的怪癖还是我从根本上错过了一些东西。

【问题讨论】:

  • 这是一种模式。迭代器产生 &i32 值,因此您进行模式匹配以获取 i32 而不是 &i32

标签: rust


【解决方案1】:

Rust 中的所有变量赋值,包括 for 循环中的循环变量和函数参数,都是使用 模式匹配 进行赋值的。分配的值与目标模式匹配,Rust 尝试填充“空白”,即目标变量名称,以一种替换值使模式匹配值的方式。让我们看几个例子。

let x = 5;

这是最简单的情况。很明显,用5 替换x 会使双方匹配。

if let Some(x) = Some(5) {}

这里,x 也将变为 5,因为将该值代入模式将使双方相同。

let &x = &5;

同样,将x 设置为5 时,两侧匹配。

if let (Some(&x), &Some(y)) = (Some(&5), &Some(6)) {}

此赋值导致x = 5y = 6,因为将这些值代入模式会使双方匹配。

让我们将它应用到您的 for 循环中。在每次循环迭代中,for 之后的模式与迭代器返回的下一个值相匹配。我们正在迭代 &[i32]the item type of the resulting iterator is &i32,因此迭代器在每次迭代中都会产生 &i32。此引用与模式&item 匹配。应用我们在上面看到的,这意味着item 变成了i32

请注意,分配不具有Copy 标记特征的类型的值会将该值移动到新变量中。上面的所有示例都使用整数,即Copy,因此会改为复制值。

【讨论】:

    【解决方案2】:

    这里没有魔法,纯粹的逻辑。考虑这个例子:

    let a = 1;
    let b = &a;  // b is a reference to a
    let &c = &a; // c is a copy of value a
    

    您可以将上面示例的第三行读作“将对 a 的引用分配给对 c 的引用”。这基本上创建了一个虚拟变量“对 c 的引用”,为其分配值 &a,然后取消引用它以获得 c 的值。

    let a = 1;
    let ref_c = &a;
    let c = *ref_c;
    
    // If you try to go backwards into this assignments, you get:
    let &c = &a;
    let &(*ref_c) = &a;
    let ref_c = &a; // which is exactly what it was
    

    for .. in 语法也是如此。你遍历item_ref,但是将它们分配给&item,这意味着item的类型是Item

    for item_ref in list {
      let item = *item_ref;
      ...
    }
    
    // we see that item_ref == &item, so above is same as
    for &item in list {
      ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-26
      • 2017-10-07
      • 1970-01-01
      • 2013-02-16
      • 1970-01-01
      • 2023-01-13
      • 2016-05-09
      • 2015-10-21
      相关资源
      最近更新 更多