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
,2
和3
綁定。向量由三部分組成,即指向存儲器中指向存儲在內存中的數據的指針,長度和向量的容量。 這些部分存儲在堆棧中,而數據存儲在堆內存中,如下所示:
第2步:
在程序的第二個語句中,將v1
向量分配給向量v2
。 指針,長度和容量將複製到堆棧中,但不會將數據複製到堆內存中。現在內存的表示如下:
但是,這種表示形式可能會產生問題。 當v1
和v2
都超出範圍時,兩者都會嘗試釋放內存。 這會導致雙重空閒內存,這會導致內存損壞。
第3步:
Rust避免了第2步 條件以確保內存安全。 Rust沒有複製分配的內存,而是認爲v1
向量不再有效。 因此,當v1
超出範圍時,它不需要釋放v1
的內存。
使用複製特徵
複製特徵是一種特殊的註釋,它放在存儲在堆棧上的整數類型上。 如果在類型上使用了複製特徵,則即使在賦值操作之後也可以進一步使用舊變量。
以下是一些複製類型:
- 所有整數類型,如
u32
。 - 布爾類型-
bool
,其值爲true
或false
。 - 所有浮動類型,如
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()
函數傳遞給變量str
。 ch
變量與值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
的值,即100
,y
變量的所有權被轉移到x
變量。