目前僅看了第二版的官方文件,記錄一下初步印象,應該還有更深刻一致的解釋,水平有限,僅供參考。
實驗環境:ubuntu17.10,rust1.18,vscode1.14 + 擴充套件rust(rls)。
btw,環境搭建順利得令人意外,rust工具鏈打造的簡潔精美,原生支援git,安裝只需一條命令:curl -ssf | sh。
資料競爭主要有三個條件:r非常重視併發,根據官方介紹:rust 是一門著眼於安全、速度和併發的程式語言。而併發需要解決的就是資料競爭問題,自然會非常重視資料的使用過程,說是小心翼翼不為過。因為資料要關聯到有名變數才能使用,所以rust在語言層面上針對變數的使用引入了解決方法,主要涉及的語法有:兩個或更多指標同時訪問同⼀資料。
⾄少有⼀個指標被寫⼊。
沒有同步資料訪問的機制。
變數宣告時,不可變(immutable,預設)、可變(mutable)
變數賦值時,所有權轉移(move)、借用(borrow)
需要注意的是,所有權僅針對複雜型別變數(在語法上,是沒有copy trait的型別),例如string、vect等在堆上儲存資料的型別,而簡單型別並不用考慮,如int、tuple、array等,原因就在於賦值時資料是如何拷貝的(雖然都是淺拷貝)。
如果熟悉淺拷貝、深拷貝的概念,自然了解,對於在堆上分配空間的複雜型別,淺拷貝會導致兩個或更多變數/指標同時指向同⼀資料,若有變數/指標作寫入操作,就會引起資料競爭問題。
所以,rust用可變/不可變、所有權、生命期等來破壞資料競爭的條件,而這些解決方案全部在編譯期搞定!
當然,代價是難以快速驗證想法,畢竟使用變數時要仔細了,否則編都編不過,期待最佳實踐和ide的支援。
let x = 3; // x 預設不可變x = 4; // 錯誤!
let x = 4; // 正確!遮蓋了原有的同名變數
let mut y = 3; // y可變
y = 4; // 正確!
fn test(v: string) ", v); } // 函式這難免有令人抓狂的感覺,還能不能愉快地玩耍了?這資料跑得跟兔子一樣,想用的時候都不知道去哪了!還可能無意中跑到函式裡直接躺屍!let x = string::from("hello"); // 所有者x(string型別)
let y = x; // 資料的所有權轉移給y!
let z = x; // 錯誤!x已不可用
test(y); // 所有權轉移,新的所有者是形參v!當函式執行完畢,v離開作用域時值被丟棄(drop)!
println!("var: {}", y); // 錯誤!y已不可用
那麼,乙個變數想多次使用怎麼辦?答案是可以借用:使⽤其值但不獲取其所有權。
fn test1(v: string) ", v); }小結:個人感覺,所有權轉移主要為併發服務,本身並不常用,畢竟資料經常要復用,沒人樂意要一直提防著資料跑哪去了,尤其在函式呼叫時。既然如此,一般把所有者保持不變,多使用引用,主要體現在複雜資料結構和函式上。fn test2(v: &string) ", v); } // 引數為引用型別
let s = string::from("hello"); // 所有者s(string型別)
let s1 = &s; // 不可變借用(borrow)!
let s2 = &s; // 借用
let s3 = s1; // 借用
test2(s1); // 借用
test1(*s1); // 錯誤!借用者s1沒有所有權,無法通過s1轉移(cannot move out of borrowed content)。
println!("var: {}", s); // 正確
但是,實際使用的情況會比較複雜,即是否可變與轉移、借用三者相互影響(混用)的情況。
從資料競爭的角度:讀讀不衝突,但讀寫、寫寫會衝突(讀即不可變,寫即可變);從實現的角度:引用是基於所有權的。
因此,可以看看哪些物件會衝突:(所有者,引用) × (不可變,可變)
首先,是否可變和所有權沒有關係。
let x = string::from("hello");雖然不可變引用(&t)沒有所有權,不會導致值被誤轉移,但借用之時要求值不能變,這意味著此時:所有權不能轉移、所有者不能改值、不能同時有可變引用!let mut z = x; // 轉移後變數x不可用
z.push_str(" z"); //正確
// 可變引用要用星號來獲得引用的內容,不可變引用不需要。
let mut x = 5;
let y = &mut x;
*y += 1;
let mut x = string::from("hello");可變引用使用上略複雜,概念上也沒有太統一的理解,這裡單獨考查。let y = &x; // 不可變引用
let z = x; // 錯誤
x.push_str(" x"); // 錯誤
let z = &mut x; // 錯誤:可變引用
「可變權」即可變引用對資料的讀寫權,具有唯一性(只有乙個可用的可變引用)和獨占性(其它讀、寫統統無效),所以對編譯影響相當大。可變引用的可變權和所有者對資料的所有權有相似性,因為可變權也有move行為。
注:官方文件裡沒有可變權的概念,但個人感覺,用這個概念比較好理解可變引用的使用,也許還有更本質的解釋,特此說明。
可變權move的兩種方式
let mut x = string::from("hello"); // 所有者x有可變權可變引用若有寫入操作則要求所有者可變。// 1. 直接轉移
let y = &mut x; // 1. y為可變引用,可變權move自x
let z = y; // 直接轉移。z為可變引用
y.push_str(" y"); // 錯誤!y的可變權已move給z
z.push_str(" z"); // 正確
// 2. 間接轉移
let mut y = &mut x; // 2. y為可變引用,可變權move自x
let w = &mut y; // 要求y可變。w為可變引用
w.push_str(" w"); // 正確
// 轉移(函式)
fn test(i: &mut string)
let mut x = string::from("hello"); // 所有者x有可變權
test(&mut x);
x.push_str(" x"); // 正確!可變權已歸還
let x = string::from("hello"); // x不可變因為都涉及到值的修改,可變引用的行為和所有者相似,而且可變權和所有權都是面向資料且唯一的。let mut z = &x; // z為不可變引用
z.push_str(" z"); // 錯誤!
let w = &mut z; // w為可變引用
w.push_str(" w"); // 錯誤!
let mut y = x; // 所有權轉移,y可變
let z = &mut y; // z為可變引用,要求y可變
z.push_str(" z"); // 正確!
let w = &z; // w 為不可變引用
w.push_str(" w"); // 錯誤!
有所有權,move後不再可用,當所有者生命期結束,值被丟棄。
讀的時候類似不可變引用,寫的時候類似可變引用。
有可變權,move自被引用者,當可變引用生命期結束,可變權自動歸還。
可變權的源頭應該來自所有者,否則意義不大。
Rust學習 所有權概念
一 什麼是所有權 一旦理解了所有權,就不需要經常考慮棧和堆了。一些語言自帶垃圾 機制 一些語言需要程式設計師手動分配記憶體和釋放 rust通過所有權系統管理記憶體,編譯器會在編譯時根據一些列規則進行檢查。在執行時,所有權系統不會減慢程式。棧 stack 所有資料必須占用已知固定的大小 堆 heap ...
rust物資重新整理機制 Rust 所有權機制
以下 簡單介紹了 rust 的所有權機制 1.rust 通過所有權機制來來管理記憶體,編譯器在編譯時就會根據所有權規則對記憶體的使用進行檢查 2.堆和棧 編譯時資料的型別大小是固定的,就是分配在棧上的 編譯時資料的型別大小不固定,就是分配在堆上的 3.作用域 4.string 記憶體 5.移動 6....
Rust 4 所有權 借用 切片
tips 棧記憶體分配大小固定,訪問時不需要額外的定址動作,故其速度快於堆記憶體分配與訪問。rust 所有權規則 所有權變更示例 fn main zs0 let zs2 zs0 println zs0 zs2 zs0,zs2 fn print zparam string i32,bool zpara...