同时修改切片/集合的多个元素

时间:2019-11-19 03:47:01

标签: rust

我有一个Vec<Vec<T>>(我知道这不理想;它来自图书馆)。我想查看外部vec中的Vec对,并将它们推向每个,像这样:

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()方法类似,但是据我所知您无法在其中获得任何 可变项。

是否有一种方法可以使借阅检查器感到满意?

2 个答案:

答案 0 :(得分:2)

通常,单个对象的不同部分的这种同时变异需要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)

答案 1 :(得分:1)

您可以使用split_at_mut来获得切片的两个不相交的可变分区。因此,您可以这样做:

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