Rust所有權


所有權是Rust程式設計語言提供的獨特功能,可在不使用垃圾收集器或指標的情況下提供記憶體安全保障。

什麼是所有權?

當程式碼塊擁有資源時,它被稱為所有權。 程式碼塊建立一個包含資源的物件。 當控制元件到達塊的末尾時,物件將被銷毀,資源將被釋放。

所有權的重點:

  • 「所有者」可以根據可變性改變變數的擁有值。
  • 所有權可以轉移到另一個變數。
  • 所有權只是在Rust中移動語意。
  • 所有權模型也保證了並行的安全性。

所有權規則

  • 在Rust中,每個值都有一個與之關聯的變數,並稱為其所有者。
  • 一次只能有一個所有者。
  • 當所有者超出範圍時,與其關聯的值將被銷毀。

所有權的例子

多個變數可以在Rust中相互互動。 下面來看一個例子:

x的值賦給變數y

let x=10;  
let y=x;

在上面的例子中,x係結到值10。然後,x的值被賦給變數y。 在這種情況下,不會建立x的副本,而是將x的值移動到變數y。 因此,x的所有權被轉移到變數y,並且變數x被銷毀。 如果嘗試重用變數x,那麼Rust會丟擲一個錯誤。可通過下面的例子來理解這一點。

fn main()  
{
    let x=10;  
    let y=x;  
    println!("value of x :{}",x);
}

編譯上面程式碼,範例的輸出如下:

記憶體和分配

在Rust中,資料可以儲存在堆疊或堆記憶體中。

堆疊儲存器: 在堆疊儲存器中,資料始終按順序放置並以相反的順序移除。 它遵循「後進先出」的原則,即始終首先刪除最後插入的資料。 堆疊記憶體是一種有組織的記憶體。 它比堆記憶體更快,因為它存取記憶體的方式。 如果在編譯時資料的大小未知,則堆記憶體用於儲存內容。

堆記憶體: 堆記憶體是有組織的記憶體。 作業系統在堆記憶體中找到一個空的空格並返回一個指標。 此過程稱為「在堆上分配」。

此圖顯示堆疊包含指標,而堆包含內容。

下面來看一個簡單的記憶體分配範例。

 fn main()  
{  
  let v1=vec![1,2,3];  
  let v2=v1;  
}

第1步:
在程式的第一個語句中,向量v1與值1,23係結。向量由三部分組成,即指向儲存器中指向儲存在記憶體中的資料的指標,長度和向量的容量。 這些部分儲存在堆疊中,而資料儲存在堆記憶體中,如下所示:

第2步:
在程式的第二個語句中,將v1向量分配給向量v2。 指標,長度和容量將複製到堆疊中,但不會將資料複製到堆記憶體中。現在記憶體的表示如下:

但是,這種表示形式可能會產生問題。 當v1v2都超出範圍時,兩者都會嘗試釋放記憶體。 這會導致雙重空閒記憶體,這會導致記憶體損壞。

第3步:
Rust避免了第2步 條件以確保記憶體安全。 Rust沒有複製分配的記憶體,而是認為v1向量不再有效。 因此,當v1超出範圍時,它不需要釋放v1的記憶體。

使用複製特徵

複製特徵是一種特殊的注釋,它放在儲存在堆疊上的整數型別上。 如果在型別上使用了複製特徵,則即使在賦值操作之後也可以進一步使用舊變數。

以下是一些複製型別:

  • 所有整數型別,如u32
  • 布林型別-bool,其值為truefalse
  • 所有浮動型別,如f64
  • 字元型別,如char

所有權和函式

當變數傳遞給函式時,所有權將移動到被呼叫函式的變數。 傳遞值的語意等於為變數賦值。

下面通過一個例子來理解這一點:

fn main()  
{  
  let s=String::from("Yiibai");  
  take_ownership(s);  
  let ch='a';  
  moves_copy(ch);  
  println!("{}",ch);  
}  
fn take_ownership(str:String)  
{  
 println!("{}",str);  
}  
fn moves_copy(c:char)  
{  
  println!("{}",c);  
}

執行上面範例程式碼,得到以下結果 -

Yiibai
a
a

在上面的例子中,字串s與值Yiibai係結,s變數的所有權通過take_ownership()函式傳遞給變數strch變數與值a係結,ch變數的所有權通過moves_copy()函式傳遞給變數c。 之後也可以使用ch變數,因為此變數的型別是「複製」特徵。

返回值和範圍

從函式返回值也會轉移所有權。看看這個範例:

fn main()  
{  
  let x= gives_ownership();  
  println!("value of x is {}",x);  
 }  
fn gives_ownership()->u32  
{  
     let y=100;  
     y  
}

執行上面範例程式碼,得到以下結果 -

value of x is 100

在上面的例子中,give_ownership()函式返回y的值,即100y變數的所有權被轉移到x變數。