rust book 中文翻譯

mb2x 9年前發布 | 14K 次閱讀 Rust

Rust編程語言

歡迎閱讀!這本書將教會你使用Rust編程語言。 Rust是一個注重安全與速度的現代系統編程語言,通過在沒有垃圾回收的情況下保證內存安全來實現它的目標,這使它成為一個在很多其它語言不適合的用例中 大展身手的語言:嵌入到其它語言中,在特定的時間和空間要求下編程,和編寫底層代碼,例如設備驅動和操作系統。它通過一系列的不產生運行時開銷的編譯時安 全檢查來提升目前語言所關注的這個領域,同時消除一切數據競爭。Rust同時也意在實現“零開銷抽象”,即便在這些抽象看起來比較像一個高級語言的特性。 即便如此,Rust也允許你像一個底層語言那樣進行精確的控制。

《Rust編程語言》被分為7個部分。這個介紹是第一部分。之后是:

在閱讀了介紹這部分之后,你可以根據喜好深入到“學習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中,你并不需要自己調用像mallocfree這樣的函數:編譯器靜態決定何時你需要分配和銷毀內存,并自動調用這些函數。人非圣賢孰能無過,不過編譯器永遠也不會忘記。

讓我們為例子再加一行:

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()之前離開作用域,所以我們不會碰到問題。

所有權的概念并不僅僅善于防止懸垂指針,也解決了一整個系列的相關問題,比如迭代器無效,并發和其它問題。

 本文由用戶 mb2x 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!