rust 內(nèi)存管理

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

對(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)中被借用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 《ijs》速成開發(fā)手冊(cè)3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 10...
    葉染柒丶閱讀 5,644評(píng)論 0 7
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,246評(píng)論 0 38
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,804評(píng)論 1 45
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,793評(píng)論 11 349
  • 練字靜心,而我練字也的確是為了靜心、修身。但是,剛剛練完字的我卻格外的心煩。因?yàn)榻裉斓倪@個(gè)字雖然簡(jiǎn)單,只有六畫,我...
    文小輝cool閱讀 240評(píng)論 0 0

友情鏈接更多精彩內(nèi)容