避免同时借用可变和不可变

Avoiding borrowing mutable and immutable at the same time

为了添加两个 Vecs 的元素,我写了一个像这样的函数

fn add_components(dest: &mut Vec<i32>, first: &Vec<i32>, second: &Vec<i32>){
  for i in 0..first.len() {
    dest[i] = first[i] + second[i];
  }
}

dest 是另一个 Vec.

时,这工作正常
let mut new_components = Vec::with_capacity(components.len());
Vector::add_components(&mut new_comps, &components, &other_components);

但是当我尝试就地添加时它爆炸了:

Vector::add_components(&mut components, &components, &other_components);

因为现在我借用 components 同时作为可变和不可变的。但这显然是我想要实现的目标。

对于这个问题,是否有任何不涉及不安全代码和指针魔术的常规和通用(意味着不仅涉及 Vecs)解决方案?

这个问题的另一个例子:

假设我想为像

这样的数字类型重载 AddAssign
impl AddAssign<Output=&NumericType> for NumericType {
  fn add_assign(&mut self, other: &NumericType) {
    unimplemented!() // concrete implementation is not important
  }
}

请注意,我想将引用作为第二个参数以避免复制。这在添加两个不同的对象时效果很好,但将一个对象添加到自身会创建完全相同的场景:

let mut num = NumericType{};
num += &num

我正在同时以可变和不可变的方式借用 num。所以显然这应该有效并且是安全的,但它也违反了 Rust 的借用规则。

处理这个以多种形式出现的问题的最佳做法是什么(当然除了复制之外)?

对此没有通用的解决方案。 Rust 不能在借用检查中对可变性进行一般抽象。

您需要有两个版本的函数用于就地版本和目标版本。

Rust 有严格的别名规则,所以 dest[i] = first[i] + second[i] 实际上会编译成不同的代码,这取决于编译器是否保证 destfirst 是不同的。不要试图用 unsafe 来捏造它,因为它将是未定义的行为并且会被错误编译。