所有權是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
變數。