【问题标题】:Modify multiple elements of a slice/collection at the same time [duplicate]同时修改切片/集合的多个元素[重复]
【发布时间】:2019-11-19 03:47:01
【问题描述】:

我有一个Vec<Vec<T>>(我知道这并不理想;它来自图书馆)。我想查看外部 vec 中的 Vecs 对并推送到它们中的每一个,如下所示:

let mut foo = vec![
    vec![1, 2, 3],
    vec![4, 5, 6],
    vec![7, 8, 9],
];

for i in foo.len() {
    let a = foo.get_mut(i - 1).unwrap();
    let b = foo.get_mut(i).unwrap(); // Does not work

    let val = 2; // Some computation based on contents of a & b

    a.push(val);
    b.insert(0, val);
}

当然,这样编译失败:

error[E0499]: cannot borrow `foo` as mutable more than once at a time
  --> foo.rs:6:17
   |
5  |         let a = foo.get_mut(i - 1).unwrap();
   |                 --- first mutable borrow occurs here
6  |         let b = foo.get_mut(i).unwrap(); // Does not work
   |                 ^^^ second mutable borrow occurs here
...
10 |         a.push(val);
   |         - first borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.

这与std::slice::window() 方法的模式相似,但据我所知,您无法在其中获得任何可变项。

有没有办法让借阅检查员高兴?

【问题讨论】:

    标签: rust


    【解决方案1】:

    一般来说,这种同时对单个对象的不同部分进行突变需要unsafe。编译器确实没有通用的方法来告诉您您确实在访问对象的不相交部分。

    但是,在这种情况下,有一个简单的封装应该适合您的使用。切片方法split_at_mut 使您可以获取可变切片的两半的可变切片。

    let mut foo = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    for i in 1..foo.len() {
        //   ^^^  note the change
        let (first_half, second_half) = foo.split_at_mut(i);
    
        // now `first_half` is `foo[0..i]`
        // `second_half` is `foo[i..]`
        let a = first_half.last_mut().unwrap();
        let b = second_half.first_mut().unwrap();
    
        let val = 2; // Some computation based on contents of a & b
    
        a.push(val);
        b.insert(0, val);
    }
    

    (playground)

    你可以通过推迟可变借用直到你真正改变向量来完全避免这种情况。

    let mut foo = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    for i in 1..foo.len() {
        // this could equally be written
        // let a = &foo[i - 1];
        let a = foo.get(i - 1).unwrap();
        let b = foo.get(i).unwrap();
    
        // This probably doesn't need mutable access, right?
        let val = 2; // Some computation based on contents of a & b
    
        // now borrow again, but this time mutate.
        foo[i - 1].push(val);
        foo[i].insert(0, val);
    }
    

    (playground)

    【讨论】:

    • 请在回答前用您提出的答案搜索现有问题。无需在 Stack Overflow 中多次重复此类常见问题和答案。
    【解决方案2】:

    您可以使用split_at_mut 获取切片的两个不相交的可变分区。所以你可以这样做:

    let (a,b) = foo.split_at_mut(i);
    let a = a.last_mut().unwrap();
    let b = b.first_mut().unwrap();
    

    【讨论】:

    • 请在回答前用您提出的答案搜索现有问题。无需在 Stack Overflow 中多次重复此类常见问题和答案。
    猜你喜欢
    • 2017-05-30
    • 2021-10-10
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多