1绷蹲、&變量 => 不可變取地址
1. 傳遞內存地址
fn run(x: &i32){
println!("{}", x)
}
fn main()
{
let x = 5;
run(&x);
}
? main make
rustc main.rs
./main
5
? main
2. 傳遞數組
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. 無法通過地址修改內存數據
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 變量 => 可變取地址
1. 可通過內存地址修改內存中數據
fn main()
{
let mut x = 5; // mut可變綁定
println!("x = {}", x);
{
let ptr = &mut x; // &mut 獲取可變類型的內存地址
*ptr += 1;
}
println!("x = {}", x);
}
? main make
rustc main.rs
./main
x = 5
x = 6
? main
2. 函數形參為內存地址
eg1
fn run(ptr: &mut i32)
{
*ptr += 1;
}
fn main()
{
let mut x = 5;
println!("x = {}", x);
// 先取&mut引用,再傳遞&mut引用給被調用函數
{
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毡泻、引用不被釋放的內存
1. 指向局部內存
fn main()
{
// 引用類型的變量
let y: &i32;
// 局部內存塊
{
let x = 5; // 局部內存
y = &x; // 讓外部的指針變量乏苦,指向局部內存塊
}
// 通過指針訪問已經被釋放的內存塊
println!("{}", y);
}
? main make
rustc main.rs
error[E0597]: `x` does not live long enough
--> main.rs:9:10
|
9 | y = &x; // 讓外部的指針變量,指向局部內存塊
| ^ 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
對于 y = &x; 報錯 => 使用了一個沒有生命周期的內存
borrowed value does not live long enough
對于 x 報錯 => x 已經被釋放
`x` dropped here while still borrowed
換句話說匠题,y 只在 X 存在的作用域內有效边涕。一旦 x 消失了缔赠,它將會變成一個 x 的無效引用衍锚。因此,上面代碼中的錯誤中說借用‘活的時間不夠長’嗤堰,因為它在有效的矢量的時間內是無效的戴质。
2. 引用變量在實例變量定義之前聲明
No
fn main()
{
// 先聲明指針變量
let y: &i32;
// 再定義變量分配局部棧幀內存
let x = 5;
// 賦值指針變量指向棧幀上內存地址
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
同樣是報錯
`x` does not live long enough
`x` dropped here while still borrowed
- 引用變量y先入棧,實例變量x后入棧踢匣,那么實例變量x處于棧頂
- 棧幀彈出時告匠,先彈出棧頂的實例變量x的內存塊,再彈出引用變量y的內存塊
- 就會造成引用變量y會引用一個已經被釋放的內存塊
Yes
fn main()
{
// 再定義變量分配局部棧幀內存
let x = 5;
// 先聲明指針變量
let y: &i32;
// 賦值指針變量指向棧幀上內存地址
y = &x;
}
? main make
rustc main.rs
./main
? main
4离唬、所有權的轉移與借用
1. 內存所有權
fn foo() {
let v = vec![1, 2, 3];
}
- 進入foo()時將新創(chuàng)建新的Vec對象后专,并在堆區(qū)分配三個內存單元存儲1、2输莺、3
- 由局部變量v綁定擁有Vec對象所在內存塊
- 當局部變量v超出foo()作用域時戚哎,會被自動清理掉
- 那么Vec對象所在內存塊也就失去了擁有者,所以也會被自動清理掉
2. 內存塊所有權的轉移
1. 【值賦值】方式會觸發(fā)內存塊所有權的轉移
fn main()
{
let v1 = vec![1, 2, 3]; // v1先持有vec對象內存塊
let v2 = v1; // v2也持有vec對象內存塊嫂用,但是會自動解除v1對vec對象內存塊的持有
println!("v1[0] is: {}", v1[0]); // 此時v1不能再使用vec對象內存塊
}
? main make
rustc main.rs
error[E0382]: use of moved value: `v1`
--> main.rs:5:28
|
4 | let v2 = v1; // v2也持有vec對象內存塊建瘫,但是會自動解除v1對vec對象內存塊的持有
| -- value moved here
5 | println!("v1[0] is: {}", v1[0]); // 此時v1不能再使用vec對象內存塊
| ^^ 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
核心錯誤提示:use of moved value: v1
2. 【值傳遞】方式會觸發(fā)內存塊所有權的轉移
fn take(v: Vec<i32>) {
// what happens here isn’t important.
}
fn main()
{
// mian()內變量v持有vec對象
let v = vec![1, 2, 3];
// 調用take(),使用【值傳遞】方式傳遞v持有的vec對象尸折,
// => 會觸發(fā)對vec對象所有權的轉移
// => main()中的局部變量v此時會【解除】對vec對象的所有權
take(v);
// main()內的局部變量v無法再通過v讀寫vec對象的內存
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
核心錯誤提示:use of moved value: v
3. Copy 拷貝取消默認的 Move控制權轉移
1. 基本數據類型的Copy
fn main()
{
let a = 1;
let b = a; // 并非使用的【內存所有權轉移】,而是執(zhí)行【內存塊數據的拷貝】
println!("a = {}", a); // 仍然可以使用變量a綁定的內存塊
}
? main make
rustc main.rs
./main
a = 1
? main
正常執(zhí)行殷蛇。
2. 函數返回傳入的vec對象來恢復所有權
fn foo(v: Vec<i32>) -> Vec<i32> {
// do stuff with v
v // 返回接收的vec對象实夹,恢復被掉函數中變量的所有權
}
fn main()
{
let v1 = vec![1, 2, 3];
// => v1 失去所有權
// => v2 在foo()執(zhí)行完畢后返回時,獲得所有權
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. 當vec對象入參很多時粒梦,變得很復雜
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// do stuff with v1 and v2
// 返回 v1, v2 => 為了讓主調函數中恢復對傳入的兩個vec對象的所有權
// 返回 42 => foo()運算結果值
(v1, v2, 42)
}
fn main()
{
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
// => 調用foo()時亮航,v1、v2【失去】所有權
// => foo()返回時匀们,v1缴淋、v2【恢復】所有權
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 【借用】使用權,避免因為move報錯
eg1
fn foo(v: &Vec<i32>) {
// do stuff with v
}
fn main()
{
let v1 = vec![1, 2, 3];
// => 不用再通過函數返回至接收vec對象泄朴,來恢復對vec對象內存的所有權
// => 直接傳遞【&變量】給被調用函數
// => 【&變量】只是讓被調用函數重抖,【暫時借用】使用變量的內存塊,并不涉及所有權轉移
foo(&v1);
// foo()執(zhí)行完畢后祖灰,仍然可以使用v1讀寫vec對象內存
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 引用钟沛,無法再被調用函數中修改傳入的內存
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 引用,可以在被調用函數中修改傳入的內存
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 能出現在一個作用域內
fn main()
{
// mut可變綁定
let mut x = 5;
println!("x = {}", x);
// &mut 獲取可變類型的內存地址
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 不能出現在一個作用域內
fn main()
{
// mut可變綁定
let mut x = 5;
println!("x = {}", x);
// &mut 獲取可變類型的內存地址
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
- 因為x已經被mutable
3. &var莫绣、&mut var 也不能同時出現在一個作用域
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迭代時对室,不能對容器同時進行修改
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,因為它在循環(huán)中被借用狞玛。