Rust初入门 -- 05 Rust语言之借用Ownership

Rust语言之借用Ownership

05 Borrowing

新建工程 05-borrowing

1
cargo new borrowing && mov borrowing 05-borrowing && cd 05-borrowing

src/main.rs

1
2
3
4
5
fn main() {
let a = vec![1,2,3];
let b = a;
println!("{:?} {:?}", a, b);
}

结果报错如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cargo run
error[E0382]: borrow of moved value: `a`
--> src/main.rs:4:27
|
2 | let a = vec![1,2,3];
| - move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
3 | let b = a;
| - value moved here
4 | println!("{:?} {:?}", a, b);
| ^ value borrowed here after move

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
error: could not compile `borrowing`.

To learn more, run the command again with --verbose.

那么我们将代码改成下面:
src/main.rs

1
2
3
4
5
6
fn main() {
let a = vec![1,2,3];
// let b = a; Error; value borrowed here after move
let b = &a; // 正确:增加&符号
println!("{:?} {:?}", a, b);
}

运行

1
2
3
$ cargo run
……
[1, 2, 3] [1, 2, 3]

这里就有rust语言的概念,叫借用(borrowing)

那借用(borrowing)又分两类型:

  1. 共享借用(Shared Borrowing (&T))

数据可以借用给一个或多个用户(或线程),但只准一个用户修改。

  1. 可变借用(Mutable Borrowing (&mut T))

数据可以借用给一个用户,并只准这个用户修改,同时不准其他用户访问。

借用规则如下 :

  1. 数据同一时间,只能是其中一种借用,要么是共享借用(Shared Borrowing (&T)),要么是可变借用(Mutable Borrowing (&mut T))。

  2. 借用概念适用于复制类型(Copy type )和移动类型( Move type )。
    src/main.rs

    1
    2
    3
    4
    5
    fn main() {
    let a = vec![1,2,3];
    let b = &a; // 这里是共享借用 Shared Borrowing (&T)
    println!("{:?} {:?}", a, b); // a 能正确访问到原来的数据 [1, 2, 3] [1, 2, 3]
    }

src/main.rs

1
2
3
4
5
fn main() {
let mut a = vec![1,2,3];
let b = &mut a; // 这里是可变借用 Mutable Borrowing (&mut T)
println!("{:?} {:?}", a, b); // a trying to access `a` as a shared borrow, so giving an error
}

报错如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
error[E0596]: cannot borrow `a` as mutable, as it is not declared as mutable
--> src/main.rs:3:13
|
2 | let mut a = vec![1,2,3];
| - help: consider changing this to be mutable: `mut a`
3 | let b = &mut a;
| ^^^^^^ cannot borrow as mutable

error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/main.rs:4:27
|
3 | let b = &mut a;
| ------ mutable borrow occurs here
4 | println!("{:?} {:?}", a, b);
| ^ - mutable borrow later used here
| |
| immutable borrow occurs here

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0502, E0596.
For more information about an error, try `rustc --explain E0502`.
error: could not compile `borrowing`.

To learn more, run the command again with --verbose.

可变借用,已经将所有权让给了b,那么a就不能再访问原来的数据。

要是还需要a继续可访问呢?

1
2
3
4
5
6
7
8
9
fn main() {
let mut a = vec![1,2,3];
// 增加一个括号,借用的生命周期,结束在括号范围内
{
let b = &mut a; // &mut borrow of `a` starts here
// any other code // 大括号结束后,b会把所有权还给a
}
println!("{:?}", a); // [1, 2, 3]
}

接着看函数的传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let mut a = vec![1,2,3];
{
let b = &mut a; // &mut borrow of `a` starts here
println!("b = {:?}", b);
}
println!("a = {:?}", a);

let c = get_fisrt_element(&a);
println!("c = {:?}", c);
}

fn get_fisrt_element(a: &Vec<i32>) -> i32 {
a[0]
}

1
2
3
4
5
$ cargo run
……
b = [1, 2, 3]
a = [1, 2, 3]
c = 1

要是函数内部需要修改数组a的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
let mut a = vec![1,2,3];
{
let b = &mut a; // &mut borrow of `a` starts here
println!("b = {:?}", b);
}
println!("a = {:?}", a);

let c = get_fisrt_element(&a);
println!("c = {:?}", c);
}

fn get_fisrt_element(a: &Vec<i32>) -> i32 {
a[2] = 9
a[0]
}

这时候会报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cargo run

error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
--> src/main.rs:14:5
|
13 | fn get_fisrt_element(a: &Vec<i32>) -> i32 {
| --------- help: consider changing this to be a mutable reference: `&mut std::vec::Vec<i32>`
14 | a[2] = 9;
| ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0596`.
error: could not compile `borrowing`.

To learn more, run the command again with --verbose.

共享借用是不能修改传参的值,若需要修改传参的值,需要用可变借用 &mut

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
let mut a = vec![1,2,3];
{
let b = &mut a; // &mut borrow of `a` starts here
println!("b = {:?}", b);
}
println!("a = {:?}", a); // 打印a的值

let c = get_fisrt_element(&mut a);
println!("c = {:?}", c);
println!("a = {:?}", a); // 再次打印a的值
}

fn get_fisrt_element(g: &mut Vec<i32>) -> i32 {
g[2] = 9;
g[0]
}

1
2
3
4
5
6
$ cargo run
……
b = [1, 2, 3]
a = [1, 2, 3]
c = 1
a = [1, 2, 9]

这时候发现a[2]已经修改成9

结合所有权(Ownership)和借用(Borrowing)两个概念来理解:

  1. 有所有权(Ownership),才有修改权
  2. 共享借用 &T 只是共享只读,没有修改权
  3. 可变借用 &mut ,会转交数据所有权(Ownership),所以可变 &mut 借用者borrower,拥有修改权,借用者归还数据所有权后,数据内容可能已经改变。