为什么借用检查器不明白借用切片的不同部分从根本上是可以的?
该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);
}
给出错误信息:
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`
回答
为什么借用检查器不明白借用切片的不同部分从根本上是可以的?
因为一般情况下是做不到的。当然,在这种情况下,很明显&slice[..mid]和&slice[mid..]是不相交的,但是一旦你摆脱了琐碎的情况,复杂性就会飙升,很快就变得不可能了。
这些特殊的琐碎情况没有特别实施,因为:
- 具有允许明显不相交的切片借用但不允许任何稍微复杂的语言功能是不直观的,并且可以使初学者认为他们可以做的事情比实际做的多
- 这些特殊情况实际上只能归结为几种模式,其中大部分都可以通过
split_at及其可变对应物来完成 - 没有办法可靠地将其扩展到具有
Indextrait 的任何东西,这意味着这(&slice[..mid], &slice[mid..])将是有效的,但(&vec[..mid], &vec[mid..])不会,这更加不一致。当然,这可以通过使Vec语言内在化来解决,但是VecDeque用户定义的数据结构呢?它只会导致太多的不一致,进而导致更多的不一致,这是 Rust 想要避免的。
- VecDeque still supports individual indexing, which may lead to things like `&vecdeque[0]` and `&vecdeque[1]` being disallowed despite clearly being valid. `Vec` is an entirely custom data structure, and vector slices work by [implementing the `Index` trait for ranges](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-Index%3CI%3E).