【问题标题】:Multiple mutable references in a loop循环中的多个可变引用
【发布时间】:2021-12-01 08:28:45
【问题描述】:

我正在尝试更详细地了解 Rust 的所有权和生命周期,但我对这段代码感到非常困惑:

let mut lst = vec![1, 2, 3];
let mut x = &mut 0;

for value in &mut lst {
    *value += 1;
    *x += 1;
    x = value;
}

*x += 1;
println!("{:?}", &lst);

据我了解,Rust 不允许对任何值有多个可变引用,并且对向量中元素的可变引用也借用了向量本身。所以不可能同时对向量中的两个元素进行可变引用。

但是在上面的代码中,循环体存储了一个可变引用,该引用对循环外的lst 中的元素进行了更改。然后,在下一次迭代中,它需要 anotherlst 中不同元素的可变引用,同时给我 两个 对列表中两个元素的可变引用。

所以我的问题是:为什么允许这样做?

【问题讨论】:

  • 您不仅可以同时获得对两个不同元素的可变引用。您可以同时获得对 all 元素的可变引用:lst.iter_mut().collect::<Vec<_>>()。这是有效的,因为来自迭代器的每个可变引用都是不同的。就像您可以同时对结构中的不同字段进行可变引用一样。

标签: rust lifetime ownership


【解决方案1】:

最后你不会多次持有 mut 引用,在x = value 中,引用被移动到x。如果该行在循环中的第一个,情况会有所不同:

fn main() {
    let mut lst = vec![1, 2, 3];
    let mut x = &mut 0;

    for value in &mut lst {
        x = value;

        *value += 1;
        *x += 1;
    }

    *x += 1;
    println!("{:?}", &lst);
}

编译器当然会抱怨:

error[E0503]: cannot use `*value` because it was mutably borrowed
 --> src/main.rs:8:9
  |
6 |         x = value;
  |             ----- borrow of `*value` occurs here
7 | 
8 |         *value += 1;
  |         ^^^^^^^^^^^ use of borrowed `*value`
9 |         *x += 1;
  |         ------- borrow later used here

【讨论】:

    【解决方案2】:

    虽然 Rust 不允许您对同一值有多个可变引用,但它确实允许您对同一值的非重叠部分进行可变引用。

    例如,您可以将 &mut T 拆分为每个字段的单独可变引用,借用检查器会为您跟踪:

    struct Foo {
        x: i32,
        y: i32,
    }
    
    let mut foo = Foo { x: 0, y : 0 };
    
    let foo_mut = &mut foo;
    let x = &mut foo_mut.x;
    let y = &mut foo_mut.y;
    
    *x = 1;
    *y = 2;
    
    println!("x = {:?}", x);     // 1
    println!("y = {:?}", y);     // 2
    println!("foo = {:?}", foo); // Foo { x: 1, y: 2 }
    

    同样,您可以使用 split_at_mutsplit_first_mut 之类的方法拆分可变切片引用 &mut [T],它们都为您提供了两个不重叠的切片可变引用。

    其实可变切片的迭代可以使用split_first_mut来实现:

    let mut lst = vec![1, 2, 3];
    let mut x = &mut 0;
    
    let mut rest = &mut *lst;
    while let Some((value, rest_)) = rest.split_first_mut() {
        rest = rest_;
    
        *value += 1;
        *x += 1;
        x = value;
    }
    
    *x += 1;
    println!("{:?}", &lst);
    

    所以&mut [T](和&mut Vec<T>)的迭代器可以提供多个共存的可变引用,只要这些可变引用指向向量的不同部分并且不重叠。

    【讨论】:

    • 很好的解释:D
    • @Mark 你完全正确,谢谢!
    • 可变切片的非重叠部分怎么样?
    • @GuerlandoOCs 是的,您可以对切片的非重叠部分有多个可变引用,并且您可以使用例如split_at_mut 在安全的 Rust 中构造这些引用。
    猜你喜欢
    • 2011-05-08
    • 2021-08-11
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    • 1970-01-01
    相关资源
    最近更新 更多