为什么借用检查器不明白借用切片的不同部分从根本上是可以的?

hkB*_*Bst 5 rust borrow-checker

split_at_mut函数(用于在索引处拆分可变切片)需要实现不安全的代码(根据 Rust 书)。但书中也说:“借用切片的不同部分从根本上是可以的,因为两个切片不重叠”。

我的问题:为什么借用检查器不明白借用切片的不同部分从根本上是可以的?(是否有原因阻止借用检查器理解此规则,或者只是由于某种原因尚未实施?)

使用 Rust 1.48 尝试建议的代码仍然会导致书中显示的错误:

fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = slice.len();

    assert!(mid <= len);

    (&mut slice[..mid], &mut slice[mid..])
}

fn main() {
    let mut vector = vec![1, 2, 3, 4, 5, 6];
    let (left, right) = split_at_mut(&mut vector, 3);
    println!("{:?}, {:?}", left, right);
}
Run Code Online (Sandbox Code Playgroud)

给出错误信息:

error[E0499]: cannot borrow `*slice` as mutable more than once at a time
 --> src/main.rs:6:30
  |
1 | fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
  |                        - let's call the lifetime of this reference `'1`
...
6 |     (&mut slice[..mid], &mut slice[mid..])
  |     -------------------------^^^^^--------
  |     |     |                  |
  |     |     |                  second mutable borrow occurs here
  |     |     first mutable borrow occurs here
  |     returning this value requires that `*slice` is borrowed for `'1`
Run Code Online (Sandbox Code Playgroud)

Apl*_*123 8

为什么借用检查器不明白借用切片的不同部分从根本上是可以的?

因为一般情况下是做不到的。当然,在这种情况下,很明显&slice[..mid]&slice[mid..]是不相交的,但是一旦你摆脱了琐碎的情况,复杂性就会飙升,很快就变得不可能了。

这些特殊的琐碎情况没有特别实施,因为:

  1. 具有允许明显不相交的切片借用但不允许任何稍微复杂的语言功能是不直观的,并且可以使初学者认为他们可以做的事情比实际做的多
  2. 这些特殊情况实际上只能归结为几种模式,其中大部分都可以通过split_at及其可变对应物来完成
  3. 没有办法可靠地将其扩展到具有Indextrait 的任何东西,这意味着这(&slice[..mid], &slice[mid..])将是有效的,但(&vec[..mid], &vec[mid..])不会,这更加不一致。当然,这可以通过使Vec语言内在化来解决,但是VecDeque用户定义的数据结构呢?它只会导致太多的不一致,进而导致更多的不一致,这是 Rust 想要避免的。

  • VecDeque 仍然支持单独索引,这可能会导致诸如“&amp;vecdeque[0]”和“&amp;vecdeque[1]”之类的内容被禁止,尽管它们显然是有效的。`Vec` 是一个完全自定义的数据结构,向量切片通过[实现范围的 `Index` 特征](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-索引%3CI%3E)。 (2认同)

mac*_*azo 2

Rust\xe2\x80\x99s 借用检查器无法\xe2\x80\x99 理解你\xe2\x80\x99 正在借用切片的不同部分;它只知道你\xe2\x80\x99从同一个切片借用了两次。如果两个切片重叠怎么办?没有办法承认他们不是。(如果有的话,还没有实现)

\n

这就是不安全存在的原因:当您确定您的代码不可能产生意外行为时,尽管编译器无法授予该行为。

\n

  • @IInspectable 这对你来说是显而易见的,但对编译器来说却不然,编译器必须能够处理任意复杂的切片表达式。证明它们在一般情况下不重叠相当于停止问题,即理论上不可能。对于切片被中间元素分割的简单情况,有 `split_at_mut` ,它消除了在编译器中对此进行特殊处理的需要。 (4认同)