1. 程式人生 > 其它 >Rust基礎02-所有權規則、記憶體與分配

Rust基礎02-所有權規則、記憶體與分配

所有權規則

  1. 每個值都有一個變數,這個變數是該值的所有者
  2. 每個值同時只能有一個所有者
  3. 當所有者超出作用域(scope)時,該值將被刪除

變數作用域

Scope 就是程式中一個專案的有效範圍

fn main() {
    //s 不可用
    let s = "hello";//s 可用
    			   //可對 s 進行相關操作
} //s 作用域到此結束,s 不再可用

String 型別

字串字面值:程式裡手寫的那些字串,它們是不可變的

String型別:在Heap上分配,能夠儲存在編譯時未知數量的文字

  • 建立 String型別 值

    可以使用 from 函式從字串字面值創建出 String 型別

    fn main() {
        let s =String::from("hello");
    }
    

    其中,"::" 表示 from 是 String 型別下的函式,這類字串是可以被修改的

String型別能夠修改,字串字面量不能修改,這是因為它們的儲存方式不同

記憶體和分配

  • 字串字面值:

    在編譯時就知道它的內容,其文字內容直接被硬編碼到最終的可執行檔案中

    速度快、高效、不可變性

  • String 型別:

    支援可變性,在Heap上分配記憶體來儲存編譯時未知的文字內容

    • 作業系統必須在執行時請求記憶體

      此步通過呼叫 String::from 來實現

    • 當用完 String 後,需要使用某種方式將記憶體返回給作業系統

      但Rust採用了不同的方式:對於某個值來說,當擁有它的變數走出作用範圍時,記憶體會立即自動的交還給作業系統

      當變數走出作用域,Rust會自動呼叫 drop 函式

  • 移動(Move):

    1. 普通情況

      多個變數可以於同一個資料使用一種獨特的方式來互動

      let x = 5;
      let y = x;
      

      整數是已知且固定大小的簡單的值,這兩個5被壓入Stack中

    2. String 版本

      let s1 = String::from("hello");
      let s2 = s1;
      

      一個String由三部分組成:

      • 一個指向存放字串內容的記憶體的指標

      • 一個長度

        長度len,就是存放字串內容所需的位元組數

      • 一個容量

        容量capacity,指String從作業系統總共獲得記憶體的總位元組數

      以上三部分放在 Stack 上,存放字串內容的部分在 Heap 上

      當把 s1 賦給 s2,String 的資料被複制了一份:

      • 在 Stack 上覆制了一份指標、長度、容量

      • 並沒有複製指標所指向的 Heap 上的資料

      當變數離開作用域時,Rust 會自動呼叫 drop 函式,並將變數使用的 Heap 記憶體釋放

      當s1、s2離開作用域時,它們都會嘗試釋放相同的記憶體:

      這會引起嚴重的BUG:二次釋放(double free)bug

      因此,Rust為了保證記憶體安全

      1. Rust 沒有嘗試複製被分配的記憶體

      2. Rust 讓 s1 失效,當 s1 離開作用域時,Rust不需要釋放任何東西

      引申:淺拷貝與深拷貝

  • 克隆(Clone):

    若有意對 Heap 上的 String 資料進行深度拷貝,而不僅僅是 Stack 上的資料,可以使用 clone 方法

    這種方法較為耗費資源且針對 Heap 上的資料進行操作

  • 複製(Copy):對 Stack 上的資料進行操作

    Copy trait,可以用於像整數這樣完全存放在 Stack 上的型別

    • 如果一個型別實現了 Copy 這個 trait,那麼舊的變數在賦值後仍然可用

    • 但若一個型別或該型別的一部分已實現了 Drop trait,那麼 Rust 不允許讓它再去實現 Copy trait 了

    任何簡單標量的組合型別都可以是 Copy 的,任何需要分配記憶體或某種資源的都不是 Copy 的

    一些擁有 Copy trait 的型別:

    • 所有的整數型別,例如 u32
    • 布林型別
    • 字元型別
    • 所有的浮點型別,例如 f64
    • 元組,如果其所有的欄位都是 Copy 的