1、&變量 => 不可變?nèi)〉刂?/h2>
1. 傳遞內(nèi)存地址
fn run(x: &i32){
println!("{}", x)
}
fn main()
{
let x = 5;
run(&x);
}
? main make
rustc main.rs
./main
5
? main
2. 傳遞數(shù)組
fn foo(s: &[i32]) {
println!("{:?}", s)
}
fn main()
{
// Vec<T> implements Deref<Target=[T]>
let owned = vec![1, 2, 3];
foo(&owned);
}
? main make
rustc main.rs
./main
[1, 2, 3]
? main
3. 無法通過地址修改內(nèi)存數(shù)據(jù)
fn run(x: &i32){
x += 1; // error:
println!("{}", x)
}
fn main()
{
let mut x = 5;
run(&x);
}
? main make
rustc main.rs
error[E0368]: binary assignment operation `+=` cannot be applied to type `&i32`
--> main.rs:2:3
|
2 | x += 1; // error:
| -^^^^^
| |
| cannot use `+=` on type `&i32`
error: aborting due to previous error
make: *** [all] Error 101
? main
2、&mut 變量 => 可變?nèi)〉刂?/h2>
1. 可通過內(nèi)存地址修改內(nèi)存中數(shù)據(jù)
fn main()
{
let mut x = 5; // mut可變綁定
println!("x = {}", x);
{
let ptr = &mut x; // &mut 獲取可變類型的內(nèi)存地址
*ptr += 1;
}
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
2. 函數(shù)形參為內(nèi)存地址
eg1
fn run(ptr: &mut i32)
{
*ptr += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
// 先取&mut引用,再傳遞&mut引用給被調(diào)用函數(shù)
{
let ptr = &mut x;
run(ptr);
}
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
eg2
fn run(ptr: &mut i32)
{
*ptr += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
// 一步傳地址
run(&mut x);
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
3、引用不被釋放的內(nèi)存
1. 指向局部?jī)?nèi)存
fn main()
{
// 引用類型的變量
let y: &i32;
// 局部?jī)?nèi)存塊
{
let x = 5; // 局部?jī)?nèi)存
y = &x; // 讓外部的指針變量,指向局部?jī)?nèi)存塊
}
// 通過指針訪問已經(jīng)被釋放的內(nèi)存塊
println!("{}", y);
}
? main make
rustc main.rs
error[E0597]: `x` does not live long enough
--> main.rs:9:10
|
9 | y = &x; // 讓外部的指針變量,指向局部?jī)?nèi)存塊
| ^ borrowed value does not live long enough
10 | }
| - `x` dropped here while still borrowed
...
14 | }
| - borrowed value needs to live until here
error: aborting due to previous error
make: *** [all] Error 101
? main
fn run(x: &i32){
println!("{}", x)
}
fn main()
{
let x = 5;
run(&x);
}
? main make
rustc main.rs
./main
5
? main
fn foo(s: &[i32]) {
println!("{:?}", s)
}
fn main()
{
// Vec<T> implements Deref<Target=[T]>
let owned = vec![1, 2, 3];
foo(&owned);
}
? main make
rustc main.rs
./main
[1, 2, 3]
? main
fn run(x: &i32){
x += 1; // error:
println!("{}", x)
}
fn main()
{
let mut x = 5;
run(&x);
}
? main make
rustc main.rs
error[E0368]: binary assignment operation `+=` cannot be applied to type `&i32`
--> main.rs:2:3
|
2 | x += 1; // error:
| -^^^^^
| |
| cannot use `+=` on type `&i32`
error: aborting due to previous error
make: *** [all] Error 101
? main
1. 可通過內(nèi)存地址修改內(nèi)存中數(shù)據(jù)
fn main()
{
let mut x = 5; // mut可變綁定
println!("x = {}", x);
{
let ptr = &mut x; // &mut 獲取可變類型的內(nèi)存地址
*ptr += 1;
}
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
2. 函數(shù)形參為內(nèi)存地址
eg1
fn run(ptr: &mut i32)
{
*ptr += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
// 先取&mut引用,再傳遞&mut引用給被調(diào)用函數(shù)
{
let ptr = &mut x;
run(ptr);
}
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
eg2
fn run(ptr: &mut i32)
{
*ptr += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
// 一步傳地址
run(&mut x);
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
3、引用不被釋放的內(nèi)存
1. 指向局部?jī)?nèi)存
fn main()
{
// 引用類型的變量
let y: &i32;
// 局部?jī)?nèi)存塊
{
let x = 5; // 局部?jī)?nèi)存
y = &x; // 讓外部的指針變量,指向局部?jī)?nèi)存塊
}
// 通過指針訪問已經(jīng)被釋放的內(nèi)存塊
println!("{}", y);
}
? main make
rustc main.rs
error[E0597]: `x` does not live long enough
--> main.rs:9:10
|
9 | y = &x; // 讓外部的指針變量,指向局部?jī)?nèi)存塊
| ^ borrowed value does not live long enough
10 | }
| - `x` dropped here while still borrowed
...
14 | }
| - borrowed value needs to live until here
error: aborting due to previous error
make: *** [all] Error 101
? main
對(duì)于 y = &x; 報(bào)錯(cuò) => 使用了一個(gè)沒有生命周期的內(nèi)存
borrowed value does not live long enough
對(duì)于 x 報(bào)錯(cuò) => x 已經(jīng)被釋放
`x` dropped here while still borrowed
換句話說,y 只在 X 存在的作用域內(nèi)有效。一旦 x 消失了,它將會(huì)變成一個(gè) x 的無效引用。因此,上面代碼中的錯(cuò)誤中說借用‘活的時(shí)間不夠長(zhǎng)’,因?yàn)樗谟行У氖噶康臅r(shí)間內(nèi)是無效的。
2. 引用變量在實(shí)例變量定義之前聲明
No
fn main()
{
// 先聲明指針變量
let y: &i32;
// 再定義變量分配局部棧幀內(nèi)存
let x = 5;
// 賦值指針變量指向棧幀上內(nèi)存地址
y = &x;
}
? main make
rustc main.rs
error[E0597]: `x` does not live long enough
--> main.rs:10:8
|
10 | y = &x;
| ^ borrowed value does not live long enough
11 | }
| - `x` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to previous error
make: *** [all] Error 101
? main
同樣是報(bào)錯(cuò)
`x` does not live long enough
`x` dropped here while still borrowed
- 引用變量y先入棧,實(shí)例變量x后入棧,那么實(shí)例變量x處于棧頂
- 棧幀彈出時(shí),先彈出棧頂的實(shí)例變量x的內(nèi)存塊,再?gòu)棾鲆米兞縴的內(nèi)存塊
- 就會(huì)造成引用變量y會(huì)引用一個(gè)已經(jīng)被釋放的內(nèi)存塊
Yes
fn main()
{
// 再定義變量分配局部棧幀內(nèi)存
let x = 5;
// 先聲明指針變量
let y: &i32;
// 賦值指針變量指向棧幀上內(nèi)存地址
y = &x;
}
? main make
rustc main.rs
./main
? main
4、所有權(quán)的轉(zhuǎn)移與借用
1. 內(nèi)存所有權(quán)
fn foo() {
let v = vec![1, 2, 3];
}
- 進(jìn)入foo()時(shí)將新創(chuàng)建新的Vec對(duì)象,并在堆區(qū)分配三個(gè)內(nèi)存單元存儲(chǔ)1、2、3
- 由局部變量v綁定擁有Vec對(duì)象所在內(nèi)存塊
- 當(dāng)局部變量v超出foo()作用域時(shí),會(huì)被自動(dòng)清理掉
- 那么Vec對(duì)象所在內(nèi)存塊也就失去了擁有者,所以也會(huì)被自動(dòng)清理掉
2. 內(nèi)存塊所有權(quán)的轉(zhuǎn)移
1. 【值賦值】方式會(huì)觸發(fā)內(nèi)存塊所有權(quán)的轉(zhuǎn)移
fn main()
{
let v1 = vec![1, 2, 3]; // v1先持有vec對(duì)象內(nèi)存塊
let v2 = v1; // v2也持有vec對(duì)象內(nèi)存塊,但是會(huì)自動(dòng)解除v1對(duì)vec對(duì)象內(nèi)存塊的持有
println!("v1[0] is: {}", v1[0]); // 此時(shí)v1不能再使用vec對(duì)象內(nèi)存塊
}
? main make
rustc main.rs
error[E0382]: use of moved value: `v1`
--> main.rs:5:28
|
4 | let v2 = v1; // v2也持有vec對(duì)象內(nèi)存塊,但是會(huì)自動(dòng)解除v1對(duì)vec對(duì)象內(nèi)存塊的持有
| -- value moved here
5 | println!("v1[0] is: {}", v1[0]); // 此時(shí)v1不能再使用vec對(duì)象內(nèi)存塊
| ^^ value used here after move
|
= note: move occurs because `v1` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
make: *** [all] Error 101
? main
核心錯(cuò)誤提示:use of moved value: v1
2. 【值傳遞】方式會(huì)觸發(fā)內(nèi)存塊所有權(quán)的轉(zhuǎn)移
fn take(v: Vec<i32>) {
// what happens here isn’t important.
}
fn main()
{
// mian()內(nèi)變量v持有vec對(duì)象
let v = vec![1, 2, 3];
// 調(diào)用take(),使用【值傳遞】方式傳遞v持有的vec對(duì)象,
// => 會(huì)觸發(fā)對(duì)vec對(duì)象所有權(quán)的轉(zhuǎn)移
// => main()中的局部變量v此時(shí)會(huì)【解除】對(duì)vec對(duì)象的所有權(quán)
take(v);
// main()內(nèi)的局部變量v無法再通過v讀寫vec對(duì)象的內(nèi)存
println!("v[0] is: {}", v[0]);
}
? main make
rustc main.rs
error[E0382]: use of moved value: `v`
--> main.rs:16:27
|
13 | take(v);
| - value moved here
...
16 | println!("v[0] is: {}", v[0]);
| ^ value used here after move
|
= note: move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
make: *** [all] Error 101
? main
核心錯(cuò)誤提示:use of moved value: v
3. Copy 拷貝取消默認(rèn)的 Move控制權(quán)轉(zhuǎn)移
1. 基本數(shù)據(jù)類型的Copy
fn main()
{
let a = 1;
let b = a; // 并非使用的【內(nèi)存所有權(quán)轉(zhuǎn)移】,而是執(zhí)行【內(nèi)存塊數(shù)據(jù)的拷貝】
println!("a = {}", a); // 仍然可以使用變量a綁定的內(nèi)存塊
}
? main make
rustc main.rs
./main
a = 1
? main
正常執(zhí)行。
2. 函數(shù)返回傳入的vec對(duì)象來恢復(fù)所有權(quán)
fn foo(v: Vec<i32>) -> Vec<i32> {
// do stuff with v
v // 返回接收的vec對(duì)象,恢復(fù)被掉函數(shù)中變量的所有權(quán)
}
fn main()
{
let v1 = vec![1, 2, 3];
// => v1 失去所有權(quán)
// => v2 在foo()執(zhí)行完畢后返回時(shí),獲得所有權(quán)
let v2 = foo(v1);
// println!("{:?}", v1); // error: use of moved value: `v1`
println!("{:?}", v2); // ok
}
? main make
rustc main.rs
./main
[1, 2, 3]
? main
3. 當(dāng)vec對(duì)象入?yún)⒑芏鄷r(shí),變得很復(fù)雜
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// do stuff with v1 and v2
// 返回 v1, v2 => 為了讓主調(diào)函數(shù)中恢復(fù)對(duì)傳入的兩個(gè)vec對(duì)象的所有權(quán)
// 返回 42 => foo()運(yùn)算結(jié)果值
(v1, v2, 42)
}
fn main()
{
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
// => 調(diào)用foo()時(shí),v1、v2【失去】所有權(quán)
// => foo()返回時(shí),v1、v2【恢復(fù)】所有權(quán)
let (v1, v2, answer) = foo(v1, v2);
println!("answer = {:?}", answer);
println!("v1 = {:?}", v1); // ok
println!("v2 = {:?}", v2); // ok
}
? main make
rustc main.rs
./main
answer = 42
v1 = [1, 2, 3]
v2 = [1, 2, 3]
? main
4. 接收與傳遞都使用 &T 【借用】使用權(quán),避免因?yàn)閙ove報(bào)錯(cuò)
eg1
fn foo(v: &Vec<i32>) {
// do stuff with v
}
fn main()
{
let v1 = vec![1, 2, 3];
// => 不用再通過函數(shù)返回至接收vec對(duì)象,來恢復(fù)對(duì)vec對(duì)象內(nèi)存的所有權(quán)
// => 直接傳遞【&變量】給被調(diào)用函數(shù)
// => 【&變量】只是讓被調(diào)用函數(shù),【暫時(shí)借用】使用變量的內(nèi)存塊,并不涉及所有權(quán)轉(zhuǎn)移
foo(&v1);
// foo()執(zhí)行完畢后,仍然可以使用v1讀寫vec對(duì)象內(nèi)存
println!("{:?}", v1); // ok
}
? main make
rustc main.rs
./main
[1, 2, 3]
? main
eg2
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
42
}
fn main()
{
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
// 同上例
let answer = foo(&v1, &v2);
println!("answer = {:?}", answer);
println!("v1 = {:?}", v1); // ok
println!("v2 = {:?}", v2); // ok
}
? main make
rustc main.rs
./main
answer = 42
v1 = [1, 2, 3]
v2 = [1, 2, 3]
? main
5. &T 引用,無法再被調(diào)用函數(shù)中修改傳入的內(nèi)存
fn run(x: &i32){
x += 1; // error:
println!("{}", x)
}
fn main()
{
let mut x = 5;
run(&x);
}
? main make
rustc main.rs
error[E0368]: binary assignment operation `+=` cannot be applied to type `&i32`
--> main.rs:2:3
|
2 | x += 1; // error:
| -^^^^^
| |
| cannot use `+=` on type `&i32`
error: aborting due to previous error
make: *** [all] Error 101
? main
6. &mut T 引用,可以在被調(diào)用函數(shù)中修改傳入的內(nèi)存
fn run(x: &mut i32) {
*x += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
run(&mut x);
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
5、var、&var、&mut var 作用域問題
1. var、&var 能出現(xiàn)在一個(gè)作用域內(nèi)
fn main()
{
// mut可變綁定
let mut x = 5;
println!("x = {}", x);
// &mut 獲取可變類型的內(nèi)存地址
let ptr = &x;
// error: cannot borrow `x` as immutable because it is also borrowed as mutable
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 5
? main
2. var、&mut var 不能出現(xiàn)在一個(gè)作用域內(nèi)
fn main()
{
// mut可變綁定
let mut x = 5;
println!("x = {}", x);
// &mut 獲取可變類型的內(nèi)存地址
let ptr = &mut x;
// error: cannot borrow `x` as immutable because it is also borrowed as mutable
println!("x = {}", x);
}
? main make
rustc main.rs
warning: unused variable: `ptr`
--> main.rs:8:7
|
8 | let ptr = &mut x;
| ^^^
|
= note: #[warn(unused_variables)] on by default
= note: to avoid this warning, consider using `_ptr` instead
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> main.rs:11:22
|
8 | let ptr = &mut x;
| - mutable borrow occurs here
...
11 | println!("x = {}", x);
| ^ immutable borrow occurs here
12 | }
| - mutable borrow ends here
error: aborting due to previous error
make: *** [all] Error 101
? main
- 提示不能訪問x
- 因?yàn)?strong>x已經(jīng)被mutable
3. &var、&mut var 也不能同時(shí)出現(xiàn)在一個(gè)作用域
fn main()
{
// mut可變綁定
let mut x = 5;
println!("x = {}", x);
{
let ptr1 = &x; //&T
let ptr2 = &mut x; //&mut T
}
}
? main make
rustc main.rs
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> main.rs:9:21
|
8 | let ptr1 = &x;
| - immutable borrow occurs here
9 | let ptr2 = &mut x;
| ^ mutable borrow occurs here
10 | }
| - immutable borrow ends here
error: aborting due to previous error
make: *** [all] Error 101
? main
4. var、&var、&mut var 分作用域操作
fn main()
{
// var => 主作用域
let mut x = 5;
println!("x = {}", x);
// &var => 子用域1
{
let ptr1 = &x;
println!("ptr1 = {}", ptr1);
}
// &mut var => 子用域2
{
let ptr2 = &mut x;
*ptr2 += 1;
}
// var => 主作用域
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
ptr1 = 5
x = 6
? main
5. 在for迭代時(shí),不能對(duì)容器同時(shí)進(jìn)行修改
fn main()
{
let mut v = vec![1, 2, 3];
for i in &v { // 讀迭代器
println!("{}", i);
v.push(34); // 寫迭代器
}
}
? main make
rustc main.rs
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> main.rs:7:5
|
5 | for i in &v { // 讀迭代器
| - immutable borrow occurs here
6 | println!("{}", i);
7 | v.push(34); // 寫迭代器
| ^ mutable borrow occurs here
8 | }
| - immutable borrow ends here
error: aborting due to previous error
make: *** [all] Error 101
? main
不能修改 V,因?yàn)樗谘h(huán)中被借用。