鍍金池/ 教程/ Java/ 介紹
While 循環(huán)
宏命令
模式
Rust 嵌入到其他語(yǔ)言
變量綁定
if
發(fā)布通道
Lang 項(xiàng)目
匹配
文檔
棧和堆
不依賴 stdlib
原始指針
條件編譯
type 別名
關(guān)聯(lián)類型
全類型
詞匯表
基本類型
Hello, world!
測(cè)試
箱和模塊
字符串
向量
引用與借用
所有權(quán)
內(nèi)斂函數(shù)
基準(zhǔn)測(cè)試
Nightly Rust
for 循環(huán)
特征
特征的對(duì)象
鏈接參數(shù)
介紹
'Deref'強(qiáng)制轉(zhuǎn)換
枚舉
內(nèi)聯(lián)匯編
泛型
方法語(yǔ)法
函數(shù)
外部函數(shù)接口
盒語(yǔ)法和模式
安裝 Rust
unsafe    
生存期
切片模式
Borrow 和 AsRef
If let
學(xué)習(xí) Rust
“常量”和“靜態(tài)”
語(yǔ)法和語(yǔ)義
迭代器
相關(guān)學(xué)術(shù)研究
通用函數(shù)調(diào)用語(yǔ)法
哲學(xué)家就餐問(wèn)題
類型轉(zhuǎn)換
閉包
并發(fā)性
Hello, Cargo!
屬性
注釋
結(jié)構(gòu)體
編譯器插件
高效 Rust
相關(guān)常量
猜謎游戲
可變性
錯(cuò)誤處理
新手入門
操作符和重載

介紹

Rust 編程語(yǔ)言

歡迎學(xué)習(xí)本教程!本教程將教你如何使用 Rust 編程語(yǔ)言。Rust 是一門強(qiáng)調(diào)安全、性能和并發(fā)性的系統(tǒng)編程語(yǔ)言。它為了達(dá)到這幾個(gè)目的,甚至沒(méi)有一個(gè)垃圾收集器。這也使 Rust 能夠應(yīng)用到其他語(yǔ)言做不到的地方:嵌入到其他語(yǔ)言,有指定空間和時(shí)間需求的程序,寫(xiě)底層代碼(如設(shè)備驅(qū)動(dòng)程序和操作系統(tǒng))。針對(duì)當(dāng)前的其他編程語(yǔ)言,Rust 做到了沒(méi)有運(yùn)行時(shí)(Runtime),沒(méi)有數(shù)據(jù)競(jìng)爭(zhēng)。 Rust 也致力于實(shí)現(xiàn)“零成本抽象”,盡管這些抽象給人的感覺(jué)像一個(gè)高級(jí)的語(yǔ)言。即使是這樣,Rust 仍然可以做到像一個(gè)低級(jí)的語(yǔ)言那樣的精確控制。

“Rust 編程語(yǔ)言”分為七個(gè)部分。本文的簡(jiǎn)介是第一個(gè)。在這之后:

  • 新手入門 - 設(shè)置您的電腦來(lái)進(jìn)行 Rust 開(kāi)發(fā)。
  • 學(xué)習(xí) Rust - 通過(guò)小型項(xiàng)目學(xué)習(xí) Rust 編程。
  • 高效的 Rust - 學(xué)習(xí)編寫(xiě)優(yōu)秀 Rust 代碼的一些高級(jí)概念。
  • 語(yǔ)法和語(yǔ)義 - Rust 的每一部分,分解成小塊來(lái)講解。
  • 每日 Rust - 尚未構(gòu)建穩(wěn)定的一些高端特性。
  • 術(shù)語(yǔ) - 本教程的相關(guān)參考科目。
  • 學(xué)術(shù)研究 - 影響 Rust 的一些著作。

閱讀本文之后,你會(huì)想了解“學(xué)習(xí) Rust”或“語(yǔ)法和語(yǔ)義”,根據(jù)你的喜好:如果你想嘗試一個(gè)項(xiàng)目,可以學(xué)習(xí) “學(xué)習(xí) Rust”章節(jié);或者如果你喜歡從小的部分開(kāi)始,徹底的學(xué)習(xí)了一個(gè)概念之后才移動(dòng)到下一個(gè)概念,那么你可以學(xué)習(xí)“語(yǔ)法和語(yǔ)義”章節(jié)。豐富的交叉聯(lián)合使這些部分連接到一起。

貢獻(xiàn)

本教程的源文件可以在 Github 上找到: github.com/rust-lang/rust/tree/master/src/doc/trpl

Rust 的一個(gè)簡(jiǎn)單介紹

Rust 是你可能會(huì)感興趣的一門語(yǔ)言么?讓我們先來(lái)看看一些能展示其一些優(yōu)勢(shì)的小代碼示例。

讓 Rust 變得獨(dú)特唯一的一個(gè)主要的概念是名稱為“所有權(quán)”的概念。思考下面這個(gè)小例子:

    fn main() {
        let mut x = vec!["Hello", "world"];
    }

這個(gè)程序有一個(gè)變量綁定名稱為 x。此綁定的值是一個(gè) Vec<T>,是我們通過(guò)在標(biāo)準(zhǔn)庫(kù)中定義的宏創(chuàng)建的一個(gè)'向量'。這個(gè)宏被稱為 Vec,我們利用!調(diào)用宏用。這遵循 Rust 的一般原則:做事情要明確。宏可以有效的做一些比函數(shù)調(diào)用更復(fù)雜的東西,所以他們外觀上來(lái)看是不一樣的。這個(gè)符號(hào)!也有助于解析,使代碼更容易編寫(xiě),這也很重要。

我們使用 mut 使 x 可變:默認(rèn)情況下,Rust 中的綁定是不可變的。我們將在后面的例子中改變此向量。

另外值得一提的是,在這里我們不需要標(biāo)注類型:Rust 是靜態(tài)類型,我們并不需要再明確標(biāo)注類型。Rust 有類型推斷,用以平衡強(qiáng)大的靜態(tài)類型和冗長(zhǎng)標(biāo)注類型。

Rust 更傾向于堆棧分配而不是堆分配:x 被直接放置在堆棧中。然而,Vec<T> 類型是在堆上分配的向量元素的空間。如果你不熟悉它們之間的區(qū)別,那么你現(xiàn)在可以先忽略它,或者你可以查看章節(jié)“堆棧和堆”,來(lái)了解詳細(xì)了解。作為一個(gè)系統(tǒng)編程語(yǔ)言,Rust 賦予了你如何分配內(nèi)存空間的能力,但是在我們開(kāi)始的階段,這是并不是一個(gè)大問(wèn)題。

此前,我們提到的“所有權(quán)”是鐵銹的關(guān)鍵新概念。生銹的說(shuō)法,X 被說(shuō)成“自己”的載體。這意味著,當(dāng) x 超出范圍,載體的存儲(chǔ)器將被解除分配。這是由防銹編譯確定性完成,而不是通過(guò)一個(gè)機(jī)制,諸如垃圾收集器。換句話說(shuō),在防銹,你不叫喜歡的 malloc 函數(shù)和釋放自己:編譯靜態(tài)判斷,當(dāng)你需要分配或釋放內(nèi)存,并插入這些調(diào)用本身。犯錯(cuò)是做人,但編譯器永遠(yuǎn)不會(huì)忘記。

前面我們所提到的,“所有權(quán)”是 Rust 中的一個(gè)非常重要的新概念。按照 Rust 的說(shuō)法,x 被稱為向量“所有”。這意味著當(dāng) x 超出范圍,向量的內(nèi)存將被銷毀。這樣做是由 Rust 的編譯器所決定的,而不是通過(guò)一種機(jī)制(如垃圾收集器)所決定的。換句話說(shuō),在 Rust 中,你不需要自己調(diào)用函數(shù),如 mallocfree yourself: 當(dāng)你需要分配或釋放的內(nèi)存時(shí),編譯器會(huì)自行靜態(tài)的決定并插入這些調(diào)用函數(shù)。犯錯(cuò)是人之常情,但編譯器永遠(yuǎn)不會(huì)忘記插入這些調(diào)用的函數(shù)。

讓我們?cè)谖覀兩厦娴睦又刑砑恿硗獾囊恍写a:

    fn main() {
        let mut x = vec!["Hello", "world"];

        let y = &x[0];
    }

我們?cè)诖私榻B了另外的一種綁定 ,y。在這種情況下,y 是向量第一個(gè)元素的一個(gè)“引用”。Rust 的引用與其他語(yǔ)言中的指針類似,不同的是有額外的編譯時(shí)安全檢查。特別指出的是,引用與所有權(quán)系統(tǒng)通過(guò)“借用”來(lái)相互作用,而不是通過(guò)擁有它。不同的是,當(dāng)引用超出范圍時(shí),它不會(huì)釋放底層的內(nèi)存。如果是那樣,我們將會(huì)釋放兩次內(nèi)存,這是顯然是不正確的!

讓我們來(lái)添加第三行代碼。表面上來(lái)是沒(méi)錯(cuò)的,但是它會(huì)導(dǎo)致一個(gè)編譯錯(cuò)誤:

    fn main() {
        let mut x = vec!["Hello", "world"];

        let y = &x[0];

        x.push("foo");
    }

push 是將一個(gè)元素附加到向量組末端的方法。當(dāng)我們?cè)噲D編譯這個(gè)程序時(shí),我們將得到一個(gè)錯(cuò)誤:

    error: cannot borrow `x` as mutable because it is also borrowed as immutable
        x.push("foo");
        ^
    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 編譯器給了很詳細(xì)的錯(cuò)誤,這是其中的一次。如錯(cuò)誤解釋中所說(shuō),雖然我們的綁定是可變的,但我們?nèi)圆荒苷{(diào)用 push 方法。這是因?yàn)槲覀円呀?jīng)有了一個(gè)矢量元素的引用 ,y。當(dāng)另外的一個(gè)引用存在時(shí),改變某些變量是危險(xiǎn)的行為,因?yàn)槲覀兛赡軐?dǎo)致引用的無(wú)效。在這個(gè)特定的例子中,當(dāng)創(chuàng)建向量時(shí),我們可能只分配了三個(gè)元素的空間。添加第四個(gè)元素意味著所有這些元素將會(huì)被分配一塊新的塊內(nèi)存,同時(shí)復(fù)制舊值到新內(nèi)存,更新內(nèi)部指針到新內(nèi)存。這些工作都沒(méi)有什么問(wèn)題。問(wèn)題是, y 不會(huì)更新,所以我們會(huì)有一個(gè)“懸空指針”。那就不對(duì)了。在這種情況下,任何的使用引用 y,將會(huì)導(dǎo)致錯(cuò)誤,所以編譯器已經(jīng)幫我們捕捉到了這個(gè)錯(cuò)誤。

那么,我們?nèi)绾谓鉀Q這個(gè)問(wèn)題呢?有兩種我們可以采用的方法。第一種方法,我們利用拷貝而不是一個(gè)引用:

    fn main() {
        let mut x = vec!["Hello", "world"];

        let y = x[0].clone();

        x.push("foo");
    }

在默認(rèn)情況下,Rust 有移動(dòng)語(yǔ)義,所有如果我們想要復(fù)制一些數(shù)據(jù),我們可以調(diào)用 clone() 方法。在這個(gè)例子中 ,y 不再是存儲(chǔ)在 x 中向量的一個(gè)引用,而是它的第一個(gè)元素“ Hello ”的一個(gè)副本。現(xiàn)在沒(méi)有引用,我們的 push() 方法可以很好地運(yùn)行。

如果我們真的想用一個(gè)引用,我們需要另外一種選擇:確保在我們嘗試做改變之前,我們的引用跳出其作用域。寫(xiě)法看起來(lái)像這樣:

    fn main() {
        let mut x = vec!["Hello", "world"];

        {
            let y = &x[0];
        }

        x.push("foo");
    }

我們用一組額外的大括號(hào)創(chuàng)建了一個(gè)內(nèi)部作用域。在我們調(diào)用 push() 之前,y 已經(jīng)跳出其作用域。所以這樣是可行的。

所有權(quán)的概念不僅有利于防止懸空指針,而且有利于解決與其相關(guān)的所有問(wèn)題,如迭代器失效,并發(fā)性等等。