1 let args: Vec<_> = env::args().collect();
2 let query = args[1]; // error
move
= take ownership
= 取得所有权。
borrow
= don't take ownership
= 借用。
move 常见案例
1// _Stack_ 分配的变量
2let x = 5u32;
3// *Copy* `x` 到 `y` - 所有权未发生转移,未发生 move
4let y = x;
5// 两个变量可以同时使用
6println!("x is {}, and y is {}", x, y);
7
8// `a` 是指向 _heap_ 上分配的变量的 pointer
9let a = Box::new(5i32);
10
11println!("a contains: {}", a);
12
13// *Move* `a` 到 `b`
14let b = a;
15// `a` 的 pointer 地址(不是数据)复制给了 `b`.
16// 两者都是指向同一片 heap 区域的 pointer,但是
17// `b` 现在取得了这块数据的所有权.
18
19// Error! `a` can no longer access the data, because it no longer owns the
20// heap memory
21//println!("a contains: {}", a);
22// TODO ^ 此处将会报错
1// 此函数演示如何释放一个变量拥有的内存区域
2fn destroy_box(c: Box<i32>) {
3 println!("Destroying a box that contains {}", c);
4
5 // `c` is destroyed and the memory freed
6}
borrow 常见案例
1// 这个函数发生了所有权转移,变量会被销毁
2fn eat_box_i32(boxed_i32: Box<i32>) {
3 println!("Destroying box that contains {}", boxed_i32);
4}
5
6// 这个函数只是借用了变量,不会销毁它
7fn borrow_i32(borrowed_i32: &i32) {
8 println!("This int is: {}", borrowed_i32);
9}
A borrowed value was moved out.
一个借用的变量被 move 了(你不能 move 一个 borrow 来的变量)。
错误代码示例:
1use std::cell::RefCell;
2
3struct TheDarkKnight;
4
5impl TheDarkKnight {
6 fn nothing_is_true(self) {}
7}
8
9fn main() {
10 let x = RefCell::new(TheDarkKnight);
11
12 x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
13}
这里, nothing_is_true
方法取得了 self
所有权. 但是,
self
不能被 move,因为 .borrow()
返回的是 &TheDarkKnight
,
它是一个借用的变量,所有权在 RefCell
.
有以下几种方法,可以修复这个问题:
1use std::cell::RefCell;
2
3struct TheDarkKnight;
4
5impl TheDarkKnight {
6 fn nothing_is_true(&self) {} // 不要取得所有权
7}
8
9fn main() {
10 let x = RefCell::new(TheDarkKnight);
11
12 x.borrow().nothing_is_true(); // ok!
13}
或:
1use std::cell::RefCell;
2
3struct TheDarkKnight;
4
5impl TheDarkKnight {
6 fn nothing_is_true(self) {}
7}
8
9fn main() {
10 let x = RefCell::new(TheDarkKnight);
11 let x = x.into_inner(); // 拿回了所有权
12
13 x.nothing_is_true(); // ok!
14}
或:
1use std::cell::RefCell;
2
3#[derive(Clone, Copy)] // 实现 Copy 特质
4struct TheDarkKnight;
5
6impl TheDarkKnight {
7 fn nothing_is_true(self) {}
8}
9
10fn main() {
11 let x = RefCell::new(TheDarkKnight);
12
13 x.borrow().nothing_is_true(); // ok!
14}
move 一个 mutably borrowed struct 的成员,依然会报错 E0507:
1struct TheDarkKnight;
2
3impl TheDarkKnight {
4 fn nothing_is_true(self) {}
5}
6
7struct Batcave {
8 knight: TheDarkKnight
9}
10
11fn main() {
12 let mut cave = Batcave {
13 knight: TheDarkKnight
14 };
15 let borrowed = &mut cave;
16
17 borrowed.knight.nothing_is_true(); // E0507
18}
但是如果使用 mem::replace
把一些东西放回去就没事:
1# struct TheDarkKnight;
2# impl TheDarkKnight { fn nothing_is_true(self) {} }
3# struct Batcave { knight: TheDarkKnight }
4use std::mem;
5
6let mut cave = Batcave {
7 knight: TheDarkKnight
8};
9let borrowed = &mut cave;
10
11mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
一个从 move 修改为 borrowed 的案例
- move(编译错误)
1fn main() { 2 let s1 = String::from("hello"); 3 let len = calculate_length(s1); 4 println!("The length of '{s1}' is {len}."); // error[E0382] 使用一个已经被 move 的变量 5} 6 7fn calculate_length(s: String) -> usize { 8 s.len() 9}
- borrow
1fn main() { 2 let s1 = String::from("hello"); 3 4 let len = calculate_length(&s1); 5 6 println!("The length of '{s1}' is {len}."); 7} 8 9fn calculate_length(s: &String) -> usize { 10 s.len() 11}
- borrow 后尝试修改(编译错误)
1fn main() { 2 let s = String::from("hello"); 3 change(&s); 4} 5 6fn change(some_string: &String) { 7 some_string.push_str(", world"); // error[E0596] 尝试 mut borrow 一个不能修改的变量 8}
- mutably borrow
1fn main() { 2 let mut s = String::from("hello"); 3 4 change(&mut s); 5} 6 7fn change(some_string: &mut String) { 8 some_string.push_str(", world"); 9}
要了解更多 Rust’s 的所有权设计,请移步 References & Borrowing。