a
是一种Vec<i32>
,可以在一个表达式中以可变和不可变的方式引用:
fn main() {
let mut a = vec![0, 1];
a[0] += a[1]; // OK
}
我认为编译此文件是因为i32
实现了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];
}
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
MyNum
实现了i32
,为什么我的Copy
的行为也与double[,] emptyArray = new double[usedImage.Width, usedImage.Height];
NetVips.Image emptyImage = NetVips.Image.NewFromMemory(emptyArray, usedImage.Width, usedImage.Height, 1, "uchar");
sources.Add(emptyImage);
不同?答案 0 :(得分:5)
我相信您在这里看到的是primitive types实际上没有称呼它们的std::ops
等效项。那些std::ops
可能只是为了无缝特征扩展而包含在内,等等。我认为博客文章Rust Tidbits: What Is a Lang Item?部分地解释了这一点。
我导出了您的示例that works with primitive types的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
}
导出错误代码的MIR时遇到很多困难。在没有借阅检查的情况下输出MIR对我来说是新的,我不知道该怎么做。
This游乐场有一个非常相似的东西,但是会编译:)
它给了我一个对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>)) }
}
原始案例如何通过借阅检查器?由于未调用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
...
}