我是铁 rust 新手,我不能解决这个简单的问题: 请考虑以下代码:

let mut a = vec![String::from("aa"), String::from("bb")];
a[0] += &*a[1];

Borry Checker理所当然地抱怨我在这里既有不可变的借词,也有可变的借词.它还暗示了我:

help: try adding a local storing this...
  --> src\main.rs:61:15
   |
61 |     a[0] += &*a[1];
   |               ^^^^
help: ...and then using that local here
  --> src\main.rs:61:5
   |
61 |     a[0] += &*a[1];
   |     ^^^^^^^^^^^^^^

我真的不明白那是什么意思.我真的需要克隆字符串才能执行如此简单的操作吗?(这将导致总共两个副本:进入临时的,然后回到a[0],而不是最佳的1个副本直接进入a[0])

推荐答案

天真地,就像这样(没有理由取消引用a[1]):

fn main() {
    let mut a = vec![String::from("aa"), String::from("bb")];
    a[0] += &a[1];
}

遗憾的是,正如您所注意到的,这会导致borrow 判断器出现问题.修改a[0]会不变地borrow 它,而你也需要不变地borrow a[1]来追加它.并且不允许同时不变地和不变地borrow a:

error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
 --> src/main.rs:3:14
  |
3 |     a[0] += &a[1];
  |     ---------^---
  |     |        |
  |     |        immutable borrow occurs here
  |     mutable borrow occurs here
  |     mutable borrow later used here

原因是拉斯特不知道a[0]a[1]是自变量.此行为是有意的,而且很重要,因为它可以防止某些可能导致未定义行为的情况.铁 rust 有一个零不确定的行为保证.

不过,您可以通过split_at_mut函数将数组拆分为两个独立可变的部分.这是可行的,因为铁 rust 现在可以保证这两个部分是独立的.按顺序borrow 它们使得(目前的)拉斯特不可能证明这一点.

fn main() {
    let mut a = vec![String::from("aa"), String::from("bb")];

    let (a_left, a_right) = a.split_at_mut(1);
    a_left[0] += &a_right[0];

    println!("{:?}", a);
}
["aabb", "bb"]

请注意,split_at_mut几乎是免费的.它实际上并没有复制任何东西,它只是创建了指向数组的两个非重叠部分的两个切片.它不会导致任何性能开销.

Rust相关问答推荐

如何处理动态 struct 实例化?

在特征中使用Async时,如何解决不透明类型`impl Future<;out=self>;`不满足其关联的类型边界和警告?

新创建的变量的绑定生存期

如何格式化传入Rust中mysql crate的Pool::new的字符串

有没有办法避免在While循环中多次borrow `*分支`

从Type::new()调用函数

在使用#[NO_STD]时,如何在Rust中收到紧急消息?

如何go 除多余的(0..)在迭代中,当它不被使用时?

使用 select 处理 SIGINT 和子等待!无阻塞

Rust:为什么 &str 不使用 Into

一个函数调用会产生双重borrow 错误,而另一个则不会

为什么数组不像向量那样在 for 块之后移动?

我的 Axum 处理程序无法编译:未实现 IntoResponse 特征

SDL2 没有在终端键上触发?

从 Cranelift 发出 ASM

在 Rust 中返回对枚举变体的引用是个好主意吗?

为什么这个值在上次使用后没有下降?

如何构建包含本地依赖项的 docker 镜像?

为什么这里需要类型注解?

在同一向量 Rust 中用另一个字符串扩展一个字符串