# Rust編程語言
歡迎閱讀!這本書將教會你使用[Rust編程語言](http://www.rust-lang.org/)。Rust是一個注重安全與速度的現代系統編程語言,通過在沒有垃圾回收的情況下保證內存安全來實現它的目標,這使它成為一個在很多其它語言不適合的用例中大展身手的語言:嵌入到其它語言中,在特定的時間和空間要求下編程,和編寫底層代碼,例如設備驅動和操作系統。它通過一系列的不產生運行時開銷的編譯時安全檢查來提升目前語言所關注的這個領域,同時消除一切數據競爭。Rust同時也意在實現“零開銷抽象”,即便在這些抽象看起來比較像一個高級語言的特性。即便如此,Rust也允許你像一個底層語言那樣進行精確的控制。
《Rust編程語言》被分為7個部分。這個介紹是第一部分。之后是:
* [準備](getting_started)?- 為你的電腦安裝Rust開發環境
* [學習Rust](study)?- 通過小項目來學習Rust編程
* [高效Rust](effective)?- 編寫優秀Rust代碼的高級內容
* [語法和語義](syntax_semantics)?- Rust各個部分,被拆分成小的部分講解
* [Rust開發版](nightly_rust)?- 還未出現在穩定版本中的最新功能
* [詞匯表](glossary)?- 書中使用的術語的參考
* [學院派研究](academic_research)?- 影響過Rust的文獻
在閱讀了介紹這部分之后,你可以根據喜好深入到“學習Rust”或“語法和語義”部分:如果你想通過項目深入了解,可以先選擇“學習Rust”;如果你想從頭開始,并且學習一個完整的內容再學習另一個,你可以從“語法和語義”開始。豐富的交叉連接將這些部分聯系到一起。
## 貢獻
生成這本書的源文件可以在GitHub上找到:[github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl)
## Rust簡介
Rust是你會感興趣的語言嗎?讓我們檢查一些小的代碼例子來展示它的部分威力。
使Rust顯得獨一無二的主要概念是“所有權”。考慮這個小例子:
~~~
fn main() {
let mut x = vec!["Hello", "world"];
}
~~~
這個程序創建了一個叫做`x`的[變量綁定](http://kaisery.gitbooks.io/rust-book-chinese/content/content/5.1.Variable%20Bindings%20%E5%8F%98%E9%87%8F%E7%BB%91%E5%AE%9A.md)。這個綁定的值是一個`Vec`,一個vector,我們通過一個定義在標準庫中的[宏](http://kaisery.gitbooks.io/rust-book-chinese/content/content/5.35.Macros%20%E5%AE%8F.md)來創建它。這個宏叫做`vec`,并且我們通過一個`!`調用宏。這遵循了Rust的一般原則:讓一切明了。宏可以做比函數調用復雜的多的多的工作,并且它們在視覺上也是有區別的。`!`也方便了解析,更容易編寫工具,這也是很重要的。
我們使用了`mut`來使`x`可變:再Rust中綁定是默認是不可變的。在下面的例子中這個vector是可變的。
另外值得注意的是這里我們并不需要一個類型注釋:因為Rust是靜態類型的,我們并不需要顯式的標明類型。Rust擁有類型推斷來平衡靜態類型的能力和類型注釋的冗余。
Rust與堆分配相比傾向于棧分配:`x`被直接儲存在棧上。然而,`Vec`類型在堆上為vector的元素分配了空間。如果你并不熟悉這里的區別,目前你可以忽略它,或者看看[“棧與堆”](http://kaisery.gitbooks.io/rust-book-chinese/content/content/4.1.The%20Stack%20and%20the%20Heap%20%E6%A0%88%E5%92%8C%E5%A0%86.md)。作為一個系統編程語言,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的引用類似于其它語言中的指針,不過帶有額外的編譯時安全檢查。引用用[“借用”](http://kaisery.gitbooks.io/rust-book-chinese/content/content/5.9.References%20and%20Borrowing%20%E5%BC%95%E7%94%A8%E5%92%8C%E5%80%9F%E7%94%A8.md)它指向的內容,而不是擁有它,來與所有權系統交互。這里的區別是,當一個引用離開作用域,它不會釋放之下的內存。如果它這么做了,我們會釋放兩次,這是很糟的!。
讓我們增加第三行。這看起來并不會引起錯誤,不過實際上會造成一個編譯錯誤:
~~~
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默認擁有[移動語義](http://kaisery.gitbooks.io/rust-book-chinese/content/content/5.8.Ownership%20%E6%89%80%E6%9C%89%E6%9D%83.md#移動語義),所以如果我們想要拷貝一些數據,我們調用`clone()`方法。在這個例子中,`y`不再是一個儲存在`x`中vector的一個引用,而是它第一個元素的拷貝,`"hello"`。現在我們并不擁有一個引用,所以`push()`就能正常工作。
如果我們真心需要一個引用,我們需要另一種方法:確保在我們嘗試修改之前,讓引用離開作用域。如下:
~~~
fn main() {
let mut x = vec!["Hello", "world"];
{
let y = &x[0];
}
x.push("foo");
}
~~~
我們用一對大括號創建了一個內部作用域,`y`會在我們調用`push()`之前離開作用域,所以我們不會碰到問題。
所有權的概念并不僅僅善于防止懸垂指針,也解決了一整個系列的相關問題,比如迭代器無效,并發和其它問題。
- 前言
- 1.介紹
- 2.準備
- 2.1.安裝Rust
- 2.2.Hello, world!
- 2.3.Hello, Cargo!
- 3.學習Rust
- 3.1.猜猜看
- 3.2.哲學家就餐問題
- 3.3.其它語言中的Rust
- 4.高效Rust
- 4.1.棧和堆
- 4.2.測試
- 4.3.條件編譯
- 4.4.文檔
- 4.5.迭代器
- 4.6.并發
- 4.7.錯誤處理
- 4.8.外部語言接口
- 4.9.Borrow 和 AsRef
- 4.10.發布途徑
- 5.語法和語義
- 5.1.變量綁定
- 5.2.函數
- 5.3.原生類型
- 5.4.注釋
- 5.5.If語句
- 5.6.for循環
- 5.7.while循環
- 5.8.所有權
- 5.9.引用和借用
- 5.10.生命周期
- 5.11.可變性
- 5.12.結構體
- 5.13.枚舉
- 5.14.匹配
- 5.15.模式
- 5.16.方法語法
- 5.17.Vectors
- 5.18.字符串
- 5.19.泛型
- 5.20.Traits
- 5.21.Drop
- 5.22.if let
- 5.23.trait對象
- 5.24.閉包
- 5.25.通用函數調用語法
- 5.26.包裝箱和模塊
- 5.27.`const`和`static`
- 5.28.屬性
- 5.29.`type`別名
- 5.30.類型轉換
- 5.31.關聯類型
- 5.32.不定長類型
- 5.33.運算符和重載
- 5.34.`Deref`強制多態
- 5.35.宏
- 5.36.裸指針
- 6.Rust開發版
- 6.1.編譯器插件
- 6.2.內聯匯編
- 6.3.不使用標準庫
- 6.4.固有功能
- 6.5.語言項
- 6.6.鏈接參數
- 6.7.基準測試
- 6.8.裝箱語法和模式
- 6.9.切片模式
- 6.10.關聯常量
- 7.詞匯表
- 8.學院派研究
- 勘誤