难以理解 Rust 借用系统
Troubles understanding rust borrowing system
我正在经历 rustlings exercises 但我似乎不明白借用语义是如何工作的。
我创建了这个简单的示例(检查 playground):
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec0", vec0);
println!("{} has content `{:?}`", "vec1", vec1);
}
出现以下错误:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `vec0` as immutable because it is also borrowed as mutable
--> src/main.rs:9:47
|
7 | let vec1 = &mut vec0;
| --------- mutable borrow occurs here
8 |
9 | println!("{} has content `{:?}`", "vec0", vec0);
| ^^^^ immutable borrow occurs here
10 |
11 | println!("{} has content `{:?}`", "vec1", vec1);
| ---- mutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
我虽然在借用一个值时原始绑定保留了所有权,也就是说,在 let vec1 = &mut vec0;
vec0 之后应该仍然拥有 vec。
此外,我不明白为什么在 println!("{} has content `{:?}`", "vec0", vec0)
的第 9 行会发生不可变借用。 vec 不是仍然属于 vec0 吗?
不能同时对同一个值有两个可变引用。如果您像这样重新排列函数中的行:
fn main() {
let mut vec0: Vec<i64> = Vec::new();
println!("{} has content `{:?}`", "vec0", vec0);
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec1", vec1);
}
,不会有问题,因为在那个变体 vec0
中,在创建对它的可变引用后就不会访问它。
如果 vec1
是一个普通的(不可变的)引用,即使你原来的行顺序也不会有问题,因为有多个不可变的(read-only)引用不是问题:
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &vec0;
println!("{} has content `{:?}`", "vec0", vec0);
println!("{} has content `{:?}`", "vec1", vec1);
}
引用最常用于函数参数,当您不想移动一个值,而只是传递一个引用给它时。只有当你需要改变函数内部的底层值时,你才需要使引用mutable.
你说得对 vec0
仍然是底层内存的所有者。
println!
需要借用 vec0
的原因是 println!
宏需要能够从向量中读取以便打印它,因此它需要一个 read-only参考。 read-only 引用自动创建并超出此宏的范围。
您在这里遇到编译器错误的原因是您违反了 borrow checker rules:
At any given time, you can have either one mutable reference or any number of immutable references.
了解 println
如何引用其参数的最佳方法是使用 cargo-expand
,它将显示宏展开的结果。对于您的代码,它扩展为
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &mut vec0;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", " has content `", "`\n"],
&match (&"vec0", &vec0) { // Immutable borrow
_args => [
::core::fmt::ArgumentV1::new(_args.0, ::core::fmt::Display::fmt),
::core::fmt::ArgumentV1::new(_args.1, ::core::fmt::Debug::fmt),
],
},
));
};
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", " has content `", "`\n"],
&match (&"vec1", &vec1) { // Immutable borrow
_args => [
::core::fmt::ArgumentV1::new(_args.0, ::core::fmt::Display::fmt),
::core::fmt::ArgumentV1::new(_args.1, ::core::fmt::Debug::fmt),
],
},
));
};
}
如您所见,println
对其参数采用 不可变引用 。(这意味着 vec0
stills 拥有向量)。但这里的问题是 Rust 在编译时强制执行“多个读者或单个作者”规则。只要存在对某个值的可变引用,您就不能使用所有者,直到可变引用消失。同样,只要存在对值的多个共享引用,即使它的所有者也不能修改它。
例如,这将编译,
fn main() {
let mut vec0: Vec<i64> = Vec::new();
{
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec1", vec1);
} // The mutable reference goes out of scope here.
println!("{} has content `{:?}`", "vec0", vec0);
}
我正在经历 rustlings exercises 但我似乎不明白借用语义是如何工作的。
我创建了这个简单的示例(检查 playground):
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec0", vec0);
println!("{} has content `{:?}`", "vec1", vec1);
}
出现以下错误:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `vec0` as immutable because it is also borrowed as mutable
--> src/main.rs:9:47
|
7 | let vec1 = &mut vec0;
| --------- mutable borrow occurs here
8 |
9 | println!("{} has content `{:?}`", "vec0", vec0);
| ^^^^ immutable borrow occurs here
10 |
11 | println!("{} has content `{:?}`", "vec1", vec1);
| ---- mutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
我虽然在借用一个值时原始绑定保留了所有权,也就是说,在 let vec1 = &mut vec0;
vec0 之后应该仍然拥有 vec。
此外,我不明白为什么在 println!("{} has content `{:?}`", "vec0", vec0)
的第 9 行会发生不可变借用。 vec 不是仍然属于 vec0 吗?
不能同时对同一个值有两个可变引用。如果您像这样重新排列函数中的行:
fn main() {
let mut vec0: Vec<i64> = Vec::new();
println!("{} has content `{:?}`", "vec0", vec0);
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec1", vec1);
}
,不会有问题,因为在那个变体 vec0
中,在创建对它的可变引用后就不会访问它。
如果 vec1
是一个普通的(不可变的)引用,即使你原来的行顺序也不会有问题,因为有多个不可变的(read-only)引用不是问题:
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &vec0;
println!("{} has content `{:?}`", "vec0", vec0);
println!("{} has content `{:?}`", "vec1", vec1);
}
引用最常用于函数参数,当您不想移动一个值,而只是传递一个引用给它时。只有当你需要改变函数内部的底层值时,你才需要使引用mutable.
你说得对 vec0
仍然是底层内存的所有者。
println!
需要借用 vec0
的原因是 println!
宏需要能够从向量中读取以便打印它,因此它需要一个 read-only参考。 read-only 引用自动创建并超出此宏的范围。
您在这里遇到编译器错误的原因是您违反了 borrow checker rules:
At any given time, you can have either one mutable reference or any number of immutable references.
了解 println
如何引用其参数的最佳方法是使用 cargo-expand
,它将显示宏展开的结果。对于您的代码,它扩展为
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &mut vec0;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", " has content `", "`\n"],
&match (&"vec0", &vec0) { // Immutable borrow
_args => [
::core::fmt::ArgumentV1::new(_args.0, ::core::fmt::Display::fmt),
::core::fmt::ArgumentV1::new(_args.1, ::core::fmt::Debug::fmt),
],
},
));
};
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", " has content `", "`\n"],
&match (&"vec1", &vec1) { // Immutable borrow
_args => [
::core::fmt::ArgumentV1::new(_args.0, ::core::fmt::Display::fmt),
::core::fmt::ArgumentV1::new(_args.1, ::core::fmt::Debug::fmt),
],
},
));
};
}
如您所见,println
对其参数采用 不可变引用 。(这意味着 vec0
stills 拥有向量)。但这里的问题是 Rust 在编译时强制执行“多个读者或单个作者”规则。只要存在对某个值的可变引用,您就不能使用所有者,直到可变引用消失。同样,只要存在对值的多个共享引用,即使它的所有者也不能修改它。
例如,这将编译,
fn main() {
let mut vec0: Vec<i64> = Vec::new();
{
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec1", vec1);
} // The mutable reference goes out of scope here.
println!("{} has content `{:?}`", "vec0", vec0);
}