rust所有權理解(備忘)

    最近閒的沒事,就準備學習一下rust。rust是Mozilla開發的一門編程語言。
rust是爲了多核系統而設計的一門編程語言,它因其特殊的機制有線程安全性,編譯期查出內存錯誤的優點,可能語法有着那麼點另類,但我想這不是問題。至於它和另外一門編程語言GO的優缺點,請自行了解,因爲我也是小白,並不敢發表什麼高見。
本文只是用自己的語言再次理解了一些rust的所有權機制,官方的文檔應該比我更加詳盡。有興趣的可以去看看,
地址: https://www.rust-lang.org/zh-CN/

正如上文所說,rust有編譯期查錯的能力以及線程安全的能力,這就是rust的特有機制,所有權機制。

首先我們先看一下所有權機制的規則(摘自官方文檔):
1.Rust 中的每一個值都有一個叫做它的所有者(owner)的變量。
     2.同時一次只能有一個所有者
     3.當所有者變量離開作用域,這個值將被丟棄。

         我們接下來會用代碼的形式來進行講解,不懂的可以去官方文檔看看語法。

首先我們看一段代碼
{
        let x = String::from("test");
        println!("in scope hello this is {}", x);
    }
    println!("out scope hello this is {}", x);

         當然,這段代碼是無法執行的,因爲根本無法通過編譯,報錯如下
error[E0425]: cannot find value `x` in this scope
  --> src/main.rs:13:40
   |
13 | println!("out scope hello this is {}", x);
   |                                        ^ not found in this scope
  因爲x在爲這個String的值的所有者,在所有者離開作用域後值直接被釋放了,這一點和其它編程語言是很相似的。


接下來我們看這一段代碼
let x = String::from("123");
     let y = x;
     println!("x = {}, y = {}", x, y);

你們可能此時也已經在猜測運行結果了,很遺憾,這段代碼也是無法運行的

報錯爲:
error[E0382]: use of moved value: `x`
  --> src/main.rs:11:32
   |
10 |     let y = x;
   |         - value moved here
11 |     println!("x = {}, y = {}", x, y);
   |                                ^ value used here after move
   |
   = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait

 報錯上顯示x的值被移動了,你們可能在想,這是什麼鬼。我們接下來就來扯一下數據的內存吧

實際上x是所有者,指向了堆上的一塊內存,因爲在rust中,非基本數據類型都是存儲在堆上的,其它語言基本也是這樣的。而let x = String::from("123");這個語言實際上是將x指向了那塊內存。而let y = x則是將y指向了與x指向內存相同的那塊內存。在其它語言中也是這樣的,因爲複製堆上的數據對運行效率影響很大。如果你們有其它語言的基礎,那麼這個過程其實就是淺拷貝,同時你們也應該瞭解這樣會導致什麼錯誤的出現,即任何該值的所有者均可對這塊內存進行修改甚至刪除,而rust解決了這個問題,rust使第一個變量,即x無效化了,這樣就不會出現上述的問題了,這個就是數據的移動,是不是很形象。

那麼我們再看另外一段代碼:

let x = 1;
     let y = x;
     println!("x = {}, y = {}", x, y);
是不是覺得這段代碼也不能執行,這就錯了,這段代碼可以正常執行,並且運行結果如你所想。因爲在rust中,基本數據類型是存儲這棧上的,而對棧的拷貝操作對運行效率的影響是微乎其微的,所以對棧上數據的引用都是默認是拷貝的。所以對於上一段代碼其實也是可以對x進行深拷貝從而讓它成功運行的。但是這樣正如前面所說的,會影響運行效率。所以rust爲了兼顧運行效率和安全,它使用了無效化這個方法。當然這個方法也會導致相應的問題,例如:
fn hello(str: String)
    {
        println!("{}", str);
    }
    fn test()
    {
        let x = String::from("123");
        hello(x);
        println!("x = {}", x);
    }


這個會編譯失敗,報錯爲
error[E0382]: use of moved value: `x`
  --> src/main.rs:15:24
   |
14 |     hello(x);
   |           - value moved here
15 |     println!("x = {}", x);
   |                        ^ value used here after move
   |
   = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait

因爲x的值已經被轉移到了hello函數的str參數中了,所以x無效化了,故而會導致這個錯誤。這個問題我們當然可以通過讓hello函數返回x的值來解決,但是這個解決辦法略顯蛋疼,而且rust已經爲我們解決了更好的方案了,具體的我們下篇文章再講,如果我記得寫的話(笑:-D),當然你們也可以去看rust的文檔。習慣了以rust的所有權系統來編程,你在編寫其它編程語言的時候也能寫成更加安全的代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章