为什么你可以借用一个可变引用并仍然使用两者?
Why can you borrow a mutable reference and still use both?
#[derive(Debug)]
struct Rect {
width: u32,
height: u32,
}
fn main() {
let mut r = Rect { width: 30, height: 30 };
let b = &mut r;
let c: &Rect = b;
println!("{:?},{:?}", b, c);
}
在代码中,b
是可变借用的,c
是不变借用的,所以这不应该编译,但编译和运行没有任何错误。
this shouldn't compile
为什么?是的,b
可变借用 r
。但是 c
不可变地借用了 b
,所以现在 b
是不可变地借来的,你不能改变它。
如果您尝试分配给 b
的任何字段,那么编译器将立即抛出错误。
let mut r = Rect { width: 30, height: 30 };
let b = &mut r;
let c: &Rect = b;
// This assignment will fail, as yes, `b` is a
// mutable reference but it is immutably borrowed.
b.width = 40;
println!("{:?},{:?}", b, c);
该示例与您一起删除 b
相同。你仍然无法改变 r
,即使 r
是可变的。
let mut r = Rect { width: 30, height: 30 };
let c: &Rect = &r;
// This assignment will fail for the same reason,
// `r` is a mutable reference but it is immutably borrowed.
r.width = 40;
println!("{:?},{:?}", r, c);
让我们简化您的示例并对其进行脱糖处理:
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
println!("{:?},{:?}", b, c);
}
我认为混淆的根源是 prinln!
宏看起来像一个常规函数调用,但实际上不是。如果我们用常规函数替换 println!
宏:
fn func(format: &str, b: &mut i32, c: &i32) {}
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
func("{:?},{:?}", b, c);
}
然后我们得到预期的编译器错误:
error[E0502]: cannot borrow `*b` as mutable because it is also borrowed as immutable
--> src/main.rs:7:5
|
6 | let c: &i32 = &*b;
| --- immutable borrow occurs here
7 | func("{:?},{:?}", b, c);
| ----^^^^^^^^^^^^^^^^^^^
| |
| mutable borrow occurs here
| immutable borrow later used by call
所以现在的问题变成了为什么 println!
在 func
失败的地方工作。 println!
展开来仔细看看:
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", ",", "\n"],
&match (&b, &c) { // borrows b & c again here
(arg0, arg1) => [
::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt),
::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt),
],
},
));
};
}
println!
将 &
添加到它的参数前面,所以如果我们修改 func
做同样的事情:
fn func(format: &str, b: &&mut i32, c: &&i32) {}
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
func("{:?},{:?}", &b, &c);
}
现在可以编译了。
那么我们在这里学到了什么?如果我们可变地借用一些数据,然后不变地从可变借用处借用,然后不变地借用可变借用和可变借用的不可变再借用,那么就没有违反 Rust 的所有权规则,因为不可变借用都是从当不可变借用还活着时,相同的原始可变借用不会被改变。
#[derive(Debug)]
struct Rect {
width: u32,
height: u32,
}
fn main() {
let mut r = Rect { width: 30, height: 30 };
let b = &mut r;
let c: &Rect = b;
println!("{:?},{:?}", b, c);
}
在代码中,b
是可变借用的,c
是不变借用的,所以这不应该编译,但编译和运行没有任何错误。
this shouldn't compile
为什么?是的,b
可变借用 r
。但是 c
不可变地借用了 b
,所以现在 b
是不可变地借来的,你不能改变它。
如果您尝试分配给 b
的任何字段,那么编译器将立即抛出错误。
let mut r = Rect { width: 30, height: 30 };
let b = &mut r;
let c: &Rect = b;
// This assignment will fail, as yes, `b` is a
// mutable reference but it is immutably borrowed.
b.width = 40;
println!("{:?},{:?}", b, c);
该示例与您一起删除 b
相同。你仍然无法改变 r
,即使 r
是可变的。
let mut r = Rect { width: 30, height: 30 };
let c: &Rect = &r;
// This assignment will fail for the same reason,
// `r` is a mutable reference but it is immutably borrowed.
r.width = 40;
println!("{:?},{:?}", r, c);
让我们简化您的示例并对其进行脱糖处理:
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
println!("{:?},{:?}", b, c);
}
我认为混淆的根源是 prinln!
宏看起来像一个常规函数调用,但实际上不是。如果我们用常规函数替换 println!
宏:
fn func(format: &str, b: &mut i32, c: &i32) {}
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
func("{:?},{:?}", b, c);
}
然后我们得到预期的编译器错误:
error[E0502]: cannot borrow `*b` as mutable because it is also borrowed as immutable
--> src/main.rs:7:5
|
6 | let c: &i32 = &*b;
| --- immutable borrow occurs here
7 | func("{:?},{:?}", b, c);
| ----^^^^^^^^^^^^^^^^^^^
| |
| mutable borrow occurs here
| immutable borrow later used by call
所以现在的问题变成了为什么 println!
在 func
失败的地方工作。 println!
展开来仔细看看:
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", ",", "\n"],
&match (&b, &c) { // borrows b & c again here
(arg0, arg1) => [
::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt),
::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt),
],
},
));
};
}
println!
将 &
添加到它的参数前面,所以如果我们修改 func
做同样的事情:
fn func(format: &str, b: &&mut i32, c: &&i32) {}
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
func("{:?},{:?}", &b, &c);
}
现在可以编译了。
那么我们在这里学到了什么?如果我们可变地借用一些数据,然后不变地从可变借用处借用,然后不变地借用可变借用和可变借用的不可变再借用,那么就没有违反 Rust 的所有权规则,因为不可变借用都是从当不可变借用还活着时,相同的原始可变借用不会被改变。