Ownership,Borrowing,Lifetimes
首先我們來看看:ownership(所有權)
我們來看看下面的代碼:
let a = [1, 2, 3];
let b = a;
println!("{:?} {:?}", a, b); // [1, 2, 3] [1, 2, 3]
let a = vec![1, 2, 3];
let b = a;
println!("{:?} {:?}", a, b); // Error; use of moved value: a
我們把這兩段代碼,放在vscode里去build.
第一段代碼沒有問題,第二段代碼報錯。
vscode會報錯信息:
println!("{:?} {:?}", a, b); // Error; use of moved value: `a`
| ^ value borrowed here after move
編譯器已經告訴我們原因:value borrowed here after move
也就是說a對原來數據的所有權已經move(移動)給b,這時再訪問a的值。編譯器就會報告你犯了一個嚴重錯誤。
我們用簡單的圖示來說明:
如圖,a原來有本書,現在給了b.
那現在,這本書就在b手上了。b擁有這本書。
對應代碼就是:
let a = vec![1, 2, 3];
let b = a;// a把數據給b.
那這個時候,a已經沒有對數據的所有權,就訪問不了數據,編譯器就報錯。
那為什么第一段代碼,又不報錯呢?
原來,rust中分兩種數據類型:
1.基本數據類型: 如:bool(布爾),char(字符),integer(整數),floating(浮點),arrays(數組),tuples(元組),slice(切片),字符串(str),函數指針(functions)
對基本類型的詳細說明 可以參考英文教程:
https://learning-rust.github.io/docs/a6.variable_bindings,constants_and_statics.html
或中文參考:http://wiki.jikexueyuan.com/project/rust/primitive-types.html
2.非基本類型:
即除基本類型外的其它類型,一般為引用類型。
那rust對這兩種類型會分別不同處理:
對基本類型,rust會對原來a的數據復制,並把復制數據賦值給b,並把原始數據的所有權狀態 設置為“已復制( copied )”狀態。
對非基本類型,rust會把原來a的數據移動,並把原始數據賦值給b,並把原始數據的所有權狀態 設置為“已移動( moved )”狀態。
針對這兩種處理模式,rust內部又定義為兩種類型:復制類型(Copy type ),移動類型( Move type )
但這里還要注意一點,對於函數指針類型,一般情況下為移動類型( Move type ),但如果它實現以下接口:
則它也是復制類型,執行復制的模式。
以上,就是所有權的基本概念和要點。
其實,我們重新思考多線程中的數據安全,rust的這種設計,是非常合理的。
(關於線程安全的問題,我之前寫過java的高並發與鎖的原理系列,見:https://www.cnblogs.com/gyc567/p/11014782.html)
首先,rust定義數據初始化動作為綁定,並且默認為不可變,如下:
let a =9;
a=10;//error
第二行代碼 a=10;是會報錯的。為什么?因為它是不可變的,如果要改變,就要把它定義為mut(可變),如下:
let mut a =9;
a=10;//correct
所以,rust的設計哲學就是默認所有線程操作都是不安全的。那所有數據默認為不可變,在多線程環境下,就是相當於所有線程都可以共享數據,是線程安全的,因為數據是不變的。
那回到上面的所有權的概念,復制類型(Copy type )就相當於數據共享,可以共享復制數據,但禁止寫。移動類型( Move type )就相當於獨占鎖,線程擁有這把“鎖”,才能訪問數據,否則報錯。
以上,希望對你有用。
如果遇到什么問題,歡迎加入:rust新手群,在這里我可以提供一些簡單的幫助,加微信:360369487,注明:博客園+rust