a是一个Vec<i32>可以在一个表达式中可变且不可变地引用的 a :
fn main() {
let mut a = vec![0, 1];
a[0] += a[1]; // OK
}
Run Code Online (Sandbox Code Playgroud)
我认为这个编译是因为i32implements Copy,所以我创建了另一种类型,Copy它像第一个例子一样实现和编译它,但它失败了:
use std::ops::AddAssign;
#[derive(Clone, Copy, PartialEq, Debug, Default)]
struct MyNum(i32);
impl AddAssign for MyNum {
fn add_assign(&mut self, rhs: MyNum) {
*self = MyNum(self.0 + rhs.0)
}
}
fn main() {
let mut b = vec![MyNum(0), MyNum(1)];
b[0] += b[1];
}
Run Code Online (Sandbox Code Playgroud)
error[E0502]: cannot borrow `b` as immutable because it is also borrowed as mutable
--> src/main.rs:14:13
|
14 | b[0] += b[1];
| --------^---
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
Run Code Online (Sandbox Code Playgroud)
MyNum行为与i32即使它实现的方式不同Copy?我相信你在这里看到的是原始类型实际上并没有调用它们的std::ops等价物。这些std::ops可能只是用于无缝特征扩展等。我认为博客文章Rust Tidbits: What Is a Lang Item? 部分解释了这一点。
我导出了适用于原始类型的示例的 MIR 。我有:
bb5: {
StorageDead(_9); // bb5[0]: scope 1 at src/main.rs:6:8: 6:9
_10 = CheckedAdd((*_8), move _5); // bb5[1]: scope 1 at src/main.rs:6:5: 6:17
assert(!move (_10.1: bool), "attempt to add with overflow") -> [success: bb6, unwind: bb4]; // bb5[2]: scope 1 at src/main.rs:6:5: 6:17
}
Run Code Online (Sandbox Code Playgroud)
我在为出错的代码导出 MIR 时遇到了很多困难。在没有借用检查的情况下输出 MIR 对我来说是新的,我不知道该怎么做。
这个操场有一个非常相似的东西,但编译:)
它给了我一个实际调用add_assign:
bb3: {
_8 = _9; // bb3[0]: scope 1 at src/main.rs:14:5: 14:9
StorageDead(_10); // bb3[1]: scope 1 at src/main.rs:14:8: 14:9
StorageLive(_11); // bb3[2]: scope 1 at src/main.rs:14:14: 14:22
(_11.0: i32) = const 1i32; // bb3[3]: scope 1 at src/main.rs:14:14: 14:22
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: src/main.rs:14:20: 14:21
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
_7 = const <MyNum as std::ops::AddAssign>::add_assign(move _8, move _11) -> [return: bb5, unwind: bb4]; // bb3[4]: scope 1 at src/main.rs:14:5: 14:22
// ty::Const
// + ty: for<'r> fn(&'r mut MyNum, MyNum) {<MyNum as std::ops::AddAssign>::add_assign}
// + val: Value(Scalar(<ZST>))
// mir::Constant
// + span: src/main.rs:14:5: 14:22
// + literal: Const { ty: for<'r> fn(&'r mut MyNum, MyNum) {<MyNum as std::ops::AddAssign>::add_assign}, val: Value(Scalar(<ZST>)) }
}
Run Code Online (Sandbox Code Playgroud)
原始案例如何通过借用检查器?由于add_assign未调用,因此可以在需要可变引用之前删除不可变引用。MIR 只是提前取消引用所需的位置并按值传递它。
bb3: {
_5 = (*_6); // bb3[0]: scope 1 at src/main.rs:6:13: 6:17
StorageDead(_7); // bb3[1]: scope 1 at src/main.rs:6:16: 6:17
...
}
Run Code Online (Sandbox Code Playgroud)