rust book 中文翻譯
Rust編程語言
歡迎閱讀!這本書將教會你使用Rust編程語言。 Rust是一個注重安全與速度的現代系統編程語言,通過在沒有垃圾回收的情況下保證內存安全來實現它的目標,這使它成為一個在很多其它語言不適合的用例中 大展身手的語言:嵌入到其它語言中,在特定的時間和空間要求下編程,和編寫底層代碼,例如設備驅動和操作系統。它通過一系列的不產生運行時開銷的編譯時安 全檢查來提升目前語言所關注的這個領域,同時消除一切數據競爭。Rust同時也意在實現“零開銷抽象”,即便在這些抽象看起來比較像一個高級語言的特性。 即便如此,Rust也允許你像一個底層語言那樣進行精確的控制。
《Rust編程語言》被分為7個部分。這個介紹是第一部分。之后是:
- 準備 - 為你的電腦安裝Rust開發環境
- 學習Rust - 通過小項目來學習Rust編程
- 高效Rust - 編寫優秀Rust代碼的高級內容
- 語法和語義 - Rust各個部分,被拆分成小的部分講解
- Rust開發版 - 還未出現在穩定版本中的最新功能
- 詞匯表 - 書中使用的術語的參考
- 學院派研究 - 影響過Rust的文獻
在閱讀了介紹這部分之后,你可以根據喜好深入到“學習Rust”或“語法和語義”部分:如果你想通過項目深入了解,可以先選擇“學習Rust”;如果你想從頭開始,并且學習一個完整的內容再學習另一個,你可以從“語法和語義”開始。豐富的交叉連接將這些部分聯系到一起。
貢獻
生成這本書的源文件可以在GitHub上找到:github.com/rust-lang/rust/tree/master/src/doc/trpl
Rust簡介
Rust是你會感興趣的語言嗎?讓我們檢查一些小的代碼例子來展示它的部分威力。
使Rust顯得獨一無二的主要概念是“所有權”。考慮這個小例子:
fn main() { let mut x = vec!["Hello", "world"];
}
這個程序創建了一個叫做x
的變量綁定。這個綁定的值是一個Vec<T>
,一個vector,我們通過一個定義在標準庫中的宏來創建它。這個宏叫做vec
,并且我們通過一個!
調用宏。這遵循了Rust的一般原則:讓一切明了。宏可以做比函數調用復雜的多的多的工作,并且它們在視覺上也是有區別的。!
也方便了解析,更容易編寫工具,這也是很重要的。
我們使用了mut
來使x
可變:再Rust中綁定是默認是不可變的。在下面的例子中這個vector是可變的。
另外值得注意的是這里我們并不需要一個類型注釋:因為Rust是靜態類型的,我們并不需要顯式的標明類型。Rust擁有類型推斷來平衡靜態類型的能力和類型注釋的冗余。
Rust與堆分配相比傾向于棧分配:x
被直接儲存在棧上。然而,Vec<T>
類型在堆上為vector的元素分配了空間。如果你并不熟悉這里的區別,目前你可以忽略它,或者看看“棧與堆”。作為一個系統編程語言,Rust給予你控制內存分配的能力,不過當我們上手后,這并不是什么大問題。
之前,我們提到“所有權”是Rust中的一個關鍵概念。在Rust用語中,x
被認為“擁有”這個vector。這意味著當x
離開作用域,vector的內存將被銷毀。這由Rust編譯器決定,而不是通過類似垃圾回收器這樣的機制。換句話說,在Rust中,你并不需要自己調用像malloc
和free
這樣的函數:編譯器靜態決定何時你需要分配和銷毀內存,并自動調用這些函數。人非圣賢孰能無過,不過編譯器永遠也不會忘記。
讓我們為例子再加一行:
fn main() { let mut x = vec!["Hello", "world"]; let y = &x[0];
}
我們引入了另一個綁定,y
。在這個例子中,y
是對vector第一個元素的“引用”。Rust的引用類似于其它語言中的指針,不過帶有額外的編譯時安全檢查。引用用“借用”它指向的內容,而不是擁有它,來與所有權系統交互。這里的區別是,當一個引用離開作用域,它不會釋放之下的內存。如果它這么做了,我們會釋放兩次,這是很糟的!。
讓我們增加第三行。這看起來并不會引起錯誤,不過實際上會造成一個編譯錯誤:
fn main() { let mut x = vec!["Hello", "world"]; let y = &x[0];
x.push("foo");
}
push
是vector的一個方法,它在vector的末尾附加另一個元素。當我們嘗試編譯這個程序時,我們得到一個錯誤:
error: cannot borrow `x` as mutable because it is also borrowed as immutable
x.push(4);
^
note: previous borrow of `x` occurs here; the immutable borrow prevents
subsequent moves or mutable borrows of `x` until the borrow ends let y = &x[0];
^
note: previous borrow ends here
fn main() {
}
^
噢!Rust編譯器有時給出灰常詳細的錯誤,而這就是其中之一。正如錯誤所解釋的,當我們讓綁定可變,我們仍不能調用push
。這是因為我們已經有了一個vector元素的引用,y
。
當有其它引用存在時改變值是危險的,因為我們可能使這個引用無效。在這個特定的例子中,當我們創建了vector,我們可能只分配了3個元素的空間。增加
一個元素意味著將分配一個新的能放下所有4個元素的空間,拷貝舊的值,并更新內部的指針指向這個內存。所有這些都木有問題。問題是y
并沒有被更新,很糟糕地,y
成了一個“懸垂指針”(dangling pointer)。因此,在這個例子中任何對y
的使用都會引起錯誤,而編譯器會為我們捕獲了這個錯誤。
那么我們應該如何解決這個問題呢?這里我們可以采取兩個方法。第一個方法是使用拷貝而不使用引用:
fn main() { let mut x = vec!["Hello", "world"]; let y = x[0].clone();
x.push("foo");
}
Rust默認擁有移動語義,所以如果我們想要拷貝一些數據,我們調用clone()
方法。在這個例子中,y
不再是一個儲存在x
中vector的一個引用,而是它第一個元素的拷貝,"hello"
。現在我們并不擁有一個引用,所以push()
就能正常工作。
如果我們真心需要一個引用,我們需要另一種方法:確保在我們嘗試修改之前,讓引用離開作用域。如下:
fn main() { let mut x = vec!["Hello", "world"];
{ let y = &x[0];
}
x.push("foo");
}
我們用一對大括號創建了一個內部作用域,y
會在我們調用push()
之前離開作用域,所以我們不會碰到問題。
所有權的概念并不僅僅善于防止懸垂指針,也解決了一整個系列的相關問題,比如迭代器無效,并發和其它問題。