Rust基礎筆記之淺談Ownership

寫在前面

Ownership System是Rust中最獨特和吸引人的特性,Rust也是依靠這個特性來實現他的最大的目標:內存安全,全部Rust的開發者都應該詳細瞭解它。
多麼濃厚的翻譯味道,的確本人學習Rust主要依靠官方的文檔(寫的很清楚詳細),這個系列的文章是我學習Rust的筆記,不徹底是翻譯官方文檔,但大部份內容都是來源於官方文檔,可是加上了不少本身的理解、思考和總結,這些筆記呢也都是最基本的概念,暫時並無深刻研究,但願你們在閱讀文章的時候能多去看看官方手冊,歡迎批評指正和補充。安全

Ownership(全部權)

Rust有一個很是棒的特色,那就是能在編譯的時候檢查出大多數安全隱患,這就避免了像C語言同樣,編譯一切OK,運行時來個Segment Fault,讓人不明因此,因此Rust須要一套機制來保證在編譯時期發現這些問題,這就是強大的Ownership System,它呢,包含了三個部分:app

  • Ownership
  • Borrowing
  • Lifetime

(後面都會說到),這玩意確實不怎麼好理解,得慢慢來。函數


當聲明一個變量綁定的時候,即該變量擁有了對應內存區域的全部權,當該變量超出做用域的時候,它所指向的內存就會被釋放。
固然,咱們能夠將它指派給其餘的綁定,就像這樣:學習

//the vector allocates space on the heap
let v=vec![1, 2, 3];
let v2=v;

若是在新的綁定以後調用原先的變量,就會獲得以下錯誤:this

error: use of moved value: `v`

緣由是let v2 = v;該語句將v所指向的內存區域移交給(move)了v2,之因此報錯,官方文檔的原話是:spa

When we move v to v2, it creates a copy of that pointer, for v2. Which means that there would be two pointers to the content of the vector on the heap. It would violate Rust's safety guarantees by introducing a data race. Therefore, Rust forbids using v after we’ve done the move.翻譯

意思就是說,如今有兩個指針指向了該內存區域,爲了不數據競爭,Rust是不容許使用move後的源變量。指針

這裏有一個問題就是:若是v2超出了它的做用域以後,還能調用v嗎?code

let v = vec![1,2,3];    
{
    let v2 = v;
}
println!("v[0] is {} ",v[0]);

結果是依然報錯:ip

error: use of moved value: `v`

也就是說當v2超出其做用域後,v2並不會歸還其對應的內存區域的全部權。

對於函數而言也會遇到同樣的問題:

fn take(v: Vec<i32>) {
    // what happens here isn’t important.
}

let v = vec![1, 2, 3];
take(v);
println!("v[0] is: {}", v[0]);

依然會遇到這樣的問題

error: use of moved value: `v`

你可能會以爲好像有的變量綁定就不是這樣的,好比:

let v = 1;
let v2 = v;
println!("v is {}",v);
println!("v2 is {}",v2);

這段代碼就能夠正常輸出啊。
這是由於x是i32類型的,它實現了Copy的特性,官方文檔的原話是:

In this case, v is an i32, which implements the Copy trait. This means that, just like a move, when we assign v to v2, a copy of the data is made. But, unlike a move, we can still use v afterward. This is because an i32 has no pointers to data somewhere else, copying it is a full copy.

之因此上面的代碼沒有問題,是由於它是一個徹底拷貝,連同數據也複製了一份,不存在兩個指針指向同一塊內存區域的問題,更談不上數據競爭,因此這段代碼並無Rust的安全機制,天然也就是容許的,這是和move不一樣的地方。

若是你想在v2以後還想使用v,能夠用以下的方式:

let v = vec![1,2,3];    
let v2 = v;
println!("y[0] is {} ",y[0]);
let v = v2; //交回全部權
println!("v[0] is {} ",v[0]);

這樣的語法是否是很麻煩,有沒有辦法讓v2再超出做用域後本身交回全部權呢?有來看看Borrow的概念吧。


持續更新……

相關文章
相關標籤/搜索