在 Rust 中,究竟什么是可变借用和不可变借用?
In Rust, what exactly are mutable and immutable borrows?
我坚持使用 借用 和 可变 的 Rust 概念:
#[derive(Debug)]
struct Rectangle {
height: u32,
width: u32,
}
fn mut_area(rect_mut: &mut Rectangle) -> u32 {
rect_mut.width /= 2;
rect_mut.height * rect_mut.width
}
fn mut_string(s: &mut String) -> &str {
s.push_str("!");
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect);
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
let half = mut_string(&mut s);
println!("half of the modified string: {}", half);
println!("modified s: {}", s);
}
当我尝试编译它时,编译器告诉我:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> <anon>:32:32
|
30 | let half = mut_string(&mut s);
| - mutable borrow occurs here
31 | println!("half of the modified string: {}", half);
32 | println!("modified s: {}", s);
| ^ immutable borrow occurs here
33 | }
| - mutable borrow ends here
我知道有一条关于可变引用的规则:
you can only have one mutable reference to a particular piece of data in a particular scope.
但是为什么rect
可以借而s
不能借呢?我如何在这里实现我想要的 - 在函数调用后打印修改后的字符串?
在调用带有对 rect
的可变引用的函数后可以打印 a
的原因是它 returns 一个 u32
即 Copy
able - 无需限制 rect
的进一步使用,因为在调用 mut_area
后不再借用它。
你的 mut_string
,另一方面,returns 是对其参数的引用,所以只要 half
在范围内,可变借用就一直有效。这就是为什么你不能为了 println!()
.
的目的而一成不变地借用 s
为了实现你想要的效果,我会在 mut_string
函数之外改变 s
(现在稍微不同的名字是个好主意)所以没有有效的可变借用- 它的参数可以不可变地借用:
fn mut_string(s: &str) -> &str {
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect); // rect's mutable borrow expires after this assignment
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
s.push_str("!"); // s is mutated here
let half = mut_string(&s); // s is borrowed immutably
println!("half of the modified string: {}", half);
println!("modified s: {}", s); // another immutable borrow of s
}
我坚持使用 借用 和 可变 的 Rust 概念:
#[derive(Debug)]
struct Rectangle {
height: u32,
width: u32,
}
fn mut_area(rect_mut: &mut Rectangle) -> u32 {
rect_mut.width /= 2;
rect_mut.height * rect_mut.width
}
fn mut_string(s: &mut String) -> &str {
s.push_str("!");
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect);
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
let half = mut_string(&mut s);
println!("half of the modified string: {}", half);
println!("modified s: {}", s);
}
当我尝试编译它时,编译器告诉我:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> <anon>:32:32
|
30 | let half = mut_string(&mut s);
| - mutable borrow occurs here
31 | println!("half of the modified string: {}", half);
32 | println!("modified s: {}", s);
| ^ immutable borrow occurs here
33 | }
| - mutable borrow ends here
我知道有一条关于可变引用的规则:
you can only have one mutable reference to a particular piece of data in a particular scope.
但是为什么rect
可以借而s
不能借呢?我如何在这里实现我想要的 - 在函数调用后打印修改后的字符串?
在调用带有对 rect
的可变引用的函数后可以打印 a
的原因是它 returns 一个 u32
即 Copy
able - 无需限制 rect
的进一步使用,因为在调用 mut_area
后不再借用它。
你的 mut_string
,另一方面,returns 是对其参数的引用,所以只要 half
在范围内,可变借用就一直有效。这就是为什么你不能为了 println!()
.
s
为了实现你想要的效果,我会在 mut_string
函数之外改变 s
(现在稍微不同的名字是个好主意)所以没有有效的可变借用- 它的参数可以不可变地借用:
fn mut_string(s: &str) -> &str {
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect); // rect's mutable borrow expires after this assignment
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
s.push_str("!"); // s is mutated here
let half = mut_string(&s); // s is borrowed immutably
println!("half of the modified string: {}", half);
println!("modified s: {}", s); // another immutable borrow of s
}