準備

本書第一章,將會帶領我們使用 Rust 及它的相關工具。 首先,我們會安裝 Rust。 接著,撰寫經典的「Hello World」程式。 最後,我們將談到 Cargo,它是 Rust 的建置系統跟套件管理器。

安裝 Rust

使用 Rust 的第一步就是安裝它。 一般來說,在本節你需要網路連線以執行指令,因為我們會從網路上下載 Rust。

我們將會提供許多終端機指令,這些指令每行都會以 $ 開頭。 你不用輸入這些 $ 符號,它們只是用來標示每一行指令。 在網路上的教學及範例中常使用以下的慣例:以一般使用者身分執行的指令使用 $ 標示,而以系統管理員身分執行的指令則使用 # 標示。

平台支援

Rust 編譯器能編譯並執行在大多數的平台上,但不是所有的平台都有相同的支援性。 Rust 的支援程度被分為三級。每一級都有不同的保證。

平台將以「target triple」的方式標識,這個字串是用來告知編譯器最終該產出怎樣的輸出。 而各列代表對應的元件在特定平台的支援性。

譯註:target triple 通常會依 <arch><sub>-<vendor>-<sys>-<abi> 的規則表示。 可以參考 Clang 的 說明文件

Tier 1 一級

一級平台可被認為是「被保證可建置且運行」的。 具體來說,它們都滿足以下要求:

  • 此平台的已建有自動化測試。
  • 通過測試,是能否將修改進到 rust-lang/rust repository master 分支的門檻。
  • 此平台提供官方發行版。
  • 已經有如何使用及建置此平台的文件。
Target std rustccargo notes
i686-pc-windows-msvc 32-bit MSVC (Windows 7+)
x86_64-pc-windows-msvc 64-bit MSVC (Windows 7+)
i686-pc-windows-gnu 32-bit MinGW (Windows 7+)
x86_64-pc-windows-gnu 64-bit MinGW (Windows 7+)
i686-apple-darwin 32-bit OSX (10.7+, Lion+)
x86_64-apple-darwin 64-bit OSX (10.7+, Lion+)
i686-unknown-linux-gnu 32-bit Linux (2.6.18+)
x86_64-unknown-linux-gnu 64-bit Linux (2.6.18+)

Tier 2 二級

二級平台可被認為是「被保證可以建置」的。 但因為沒有執行自動化測試,所以不保證能產生可以運行的 build,不過此平台通常運行良好,且永遠歡迎上 patches! 具體來說,這些平台被要求要符合以下各項:

  • 有自動建置,但可能沒有執行測試。
  • 能建置成功,是能否把將修改進到 rust-lang/rust repository master 分支的門檻。 請注意,這代表在某些平台上,只要標準函式庫被編譯成功即可,但其他平台將需要執行整個 bootstrap。
  • 此平台提供官方發行版。
Target std rustccargo notes
x86_64-unknown-linux-musl 64-bit Linux with MUSL
arm-linux-androideabi ARM Android
arm-unknown-linux-gnueabi ARM Linux (2.6.18+)
arm-unknown-linux-gnueabihf ARM Linux (2.6.18+)
aarch64-unknown-linux-gnu ARM64 Linux (2.6.18+)
mips-unknown-linux-gnu MIPS Linux (2.6.18+)
mipsel-unknown-linux-gnu MIPS (LE) Linux (2.6.18+)

Tier 3 三級

三級平台是那些 Rust 支援的平台,但能否成功建置或通過測試不會阻礙提交修改。 在這些平台上可運行的 builds 可能會有一些小問題,因為它們的可靠度通常由社群貢獻所決定。 此外,並不提供發行版及安裝檔,但可能在非官方的地方有提供社群產出的版本。

Target std rustccargo notes
i686-linux-android 32-bit x86 Android
aarch64-linux-android ARM64 Android
powerpc-unknown-linux-gnu PowerPC Linux (2.6.18+)
powerpc64-unknown-linux-gnu PPC64 Linux (2.6.18+)
powerpc64le-unknown-linux-gnu PPC64LE Linux (2.6.18+)
armv7-unknown-linux-gnueabihf ARMv7 Linux (2.6.18+)
i386-apple-ios 32-bit x86 iOS
x86_64-apple-ios 64-bit x86 iOS
armv7-apple-ios ARM iOS
armv7s-apple-ios ARM iOS
aarch64-apple-ios ARM64 iOS
i686-unknown-freebsd 32-bit FreeBSD
x86_64-unknown-freebsd 64-bit FreeBSD
x86_64-unknown-openbsd 64-bit OpenBSD
x86_64-unknown-netbsd 64-bit NetBSD
x86_64-unknown-bitrig 64-bit Bitrig
x86_64-unknown-dragonfly 64-bit DragonFlyBSD
x86_64-rumprun-netbsd 64-bit NetBSD Rump Kernel
x86_64-sun-solaris 64-bit Solaris/SunOS
i686-pc-windows-msvc (XP) Windows XP support
x86_64-pc-windows-msvc (XP) Windows XP support

請注意,這個表格可能會隨著時間而增長,這永遠不是三級平台最終的列表!

安裝在 Linux 或 Mac 上

如果在 Linux 或 Mac 上,我們只需要開啟終端機並輸入:

$ curl -sSf https://static.rust-lang.org/rustup.sh | sh

這樣就會下載安裝腳本,然後開始安裝。當全部完成後,你將會看到:

Welcome to Rust.

This script will download the Rust compiler and its package manager, Cargo, and
install them to /usr/local. You may install elsewhere by running this script
with the --prefix=<path> option.

The installer will run under ‘sudo’ and may ask you for your password. If you do
not want the script to run ‘sudo’ then pass it the --disable-sudo flag.

You may uninstall later by running /usr/local/lib/rustlib/uninstall.sh,
or by running this script again with the --uninstall flag.

Continue? (y/N)

接著按下 y 表示同意,接著按照提示安裝。

安裝在 Windows 上

如果你使用 Windows,請下載合適版本的 安裝檔

移除

移除 Rust 就跟安裝一樣簡單。在 Linux 或 Mac 上,只需執行移除指令就可以了:

$ sudo /usr/local/lib/rustlib/uninstall.sh

如果你是安裝 Windows 安裝檔來安裝的,請重新執行 .msi 檔,然後他就會出現移除的選項。

故障排除

當我們裝好 Rust 後,我們可以開啟 shell,然後輸入:

$ rustc --version

你將會看到版本號碼、commit hash 及 commit 的日期。

如果你成功了,代表 Rust 安裝成功了!恭喜你!

如果沒有成功,而你是使用 Windows 作業系統,請確認 Rust 有設定在你的 %PATH% 系統環境變數內。 如果沒有,重新執行安裝檔,在「Change, repair, or remove installation」頁面選擇「Change」,接著確定「Add to PATH」有裝到本機端。

Rust 不自己做 linking,所以你會需要安裝一個 linker。 做這件事會相依於你所使用的作業系統,更多細節請查閱相關文件。

如果仍然沒有成功,有許多地方可以獲得協助。 最簡單的是使用 Mibbit 連上 irc.mozilla.org 的 #rust IRC 頻道。 按下連結,然後就能跟可以幫助我們的 Rustaceans(我們用以自稱的暱稱)聊天。 其他的資源還包括了 使用者論壇Stack Overflow

安裝檔同時也安裝了一份文件的複本在本機,所以我們可以離線閱讀這份文件。 在 UNIX 系統的位置是 /usr/local/share/doc/rust。 在 Windows,文件則放在 Rust 安裝目錄下的 share/doc 目錄。

Hello, world!

現在 Rust 已經裝好了,我們將協助你開始寫你的第一個 Rust 程式。 學習一個新語言的傳統是,撰寫一個小程式,並在螢幕上印出「Hello, world!」。 本節我們會遵循這個傳統。

從這樣一個簡單小程式開始的好處,是你能很快地驗證編譯器已經安裝完成,而且正常運行。 把資訊印在螢幕上也是個未來會很常做的事情,早點練習沒什麼不好。

註:本書假設你已經有基本的指令熟悉程度。 Rust 對你的編輯器、工具、或程式碼放在何處沒有特別要求,所以如果你喜歡使用 IDE 而非 command line 介面,使用 IDE 也是個選擇。 你也許會想嘗試專為 Rust 建立的 SolidOak。 社群也開發了許多擴充功能,而且 Rust 團隊也替 許多編輯器 發佈了外掛。 配置你的編輯器或 IDE 不在本教學的範圍內,所以請依據你的設置查閱文件。

建立專案檔

首先,建立一個檔案來放程式碼。 Rust 不在乎你的程式碼放在哪,但在本書中,我建議建立一個 projects 目錄在你的 home 目錄底下,並且把所有你的專案都放在裡面。 開啟終端機並輸入以下指令來替專案建立目錄:

$ mkdir ~/projects
$ cd ~/projects
$ mkdir hello_world
$ cd hello_world

註:如果你使用 Windows 而且不是使用 PowerShell,則 ~ 可能沒有作用。 更多細節請查閱你所使用 shell 的文件。

撰寫並執行 Rust 程式

接著,建立一個新的原始碼檔案,命名為 main.rs。 Rust 的檔案永遠以 .rs 副檔名為結尾。 如果你的檔案名稱中使用了超過一個英文單字,請使用底線去區分它們;舉例來說,你應該用 hello_world.rs 來命名,而不是 helloworld.rs

現在開啟建好的 main.rs 檔案,然後輸入以下程式碼:

fn main() {
    println!("Hello, world!");
}

存檔,然後回到你的終端機視窗。 在 Linux 或 OSX 下,輸入以下指令:

$ rustc main.rs
$ ./main
Hello, world!

在 Windows 下,請把 main 換成 main.exe。 不論你的作業系統為何,你應該能看到字串 Hello, world! 印在終端機上。 如果你成功了,那麼恭喜你! 你已正式地寫出了一個 Rust 程式。 這讓你成為了 Rust 程式設計師!歡迎你!

剖析 Rust 程式

現在,讓我們來仔細檢視「Hello, world!」程式到底發生了什麼事。 這是第一塊謎團:

fn main() {

}

這幾行定義了 Rust 中的 函式(function)。 其中 main 函式比較特殊:他是所有 Rust 程式的起始點。 第一行意指「我要定義一個叫 main 的函式,它沒有參數也沒有回傳值。」 如果函式有參數的話,參數會放在括號(())中,且因為我們不回傳值,所以可以省略回傳的型態。

同時留意,函式的內容會被包在大括號({})內。 Rust 要求所有函式的內容都要用它包起來。 把第一個大括號放在函式宣告的同一行,在中間留一個空白,一般被認為是好的程式風格。

main() 函式中:

    println!("Hello, world!");

這一行負責這個小程式的全部工作:印出文字到螢幕上。 這邊有許多很重要的細節。 首先,縮排是四個空白,而不是 tabs。

第二個重要的部分是 println!() 這行。 這個在 Rust 中叫做 巨集(macro),這是 Rust 達成 metaprogramming 的方式。 如果在此處改用函式的話,看起來會像是 println()(沒有 ! 符號)。 我們將在之後討論 Rust 巨集的更多細節,但現在你只需知道,當看到 ! 的時候,代表你正在呼叫一個巨集,而不是一般的函式。

接著 "Hello, world!" 是一個 字串(string)。 在系統程式語言中,字串是個複雜到令人驚訝的主題,在此處,這是一個 靜態分配(statically allocated)的字串。 我們傳遞這個字串作為參數給 println!,然後它將字串印在螢幕上。 夠簡單吧!

程式中每一行都以分號(;)結尾。 Rust 是個 表達式導向語言(expression-oriented language),這代表大多數的東西都是表達式,而不是陳述式(statements)。 ; 代表著這個表達式已經結束,而且下一個正準備開始。 大多數 Rust 程式碼的行都是以 ; 結尾。

編譯和執行是不同的步驟

在「撰寫並執行 Rust 程式」中,我們告訴你如何執行一個新建的程式。 現在我們分解流程,檢查每一步。

執行 Rust 程式之前,你需要編譯它。 你可以使用 Rust 編譯器,輸入 rustc 指令並傳遞原始碼的檔名給它,像這樣

$ rustc main.rs

如果你有 C 或 C++ 的背景,你會注意到這跟 gccclang 很類似。 編譯成功之後,Rust 應該會輸出一個二進位執行檔,你可以在 Linux 或 OSX 下的 shell 輸入 ls 指令:

$ ls
main  main.rs

在 Windows 下,你可以輸入:

$ dir
main.exe  main.rs

這表示我們有兩個檔案:以 .rs 作為副檔名的原始檔,以及執行檔(在 Windows 是 main.exe,其他作業系統則是 main)。 接著我們唯一要做的就只剩下執行 mainmain.exe 了:

$ ./main  # or main.exe on Windows

如果 main.rs 是「Hello, world!」程式,那它會印出 Hello, world! 在終端機上。

如果你以前學的是動態語言,例如 Ruby、Python、或 JavaScript,你可能會不習慣把編譯程式和執行程式的動作分開。 Rust 是個 事先編譯(ahead-of-time compiled)的語言,你可以編譯程式,把程式給其他人,他們不用安裝 Rust 就能執行程式。 如果你給一個人 .rb.py.js 檔,他則必須要先裝好 Ruby、Python、或 JavaScript 應用,不過反之,他只需一個指令就可以編譯並執行程式。 這都是程式語言的設計中的取捨。

簡單的程式只需要用 rustc 直接編譯就好了,但隨著你的專案成長,你會希望能夠管理專案的所有選項,並且能簡單的分享程式碼給其他人和專案。 下一節,我們將會介紹給你一個叫做 Cargo 的工具,他可以幫你撰寫真實世界的 Rust 程式。

Hello, Cargo!

Cargo 是 Rust 的建置系統跟套件管理器,而且 Rustaceans 會使用 Cargo 去管理他們的 Rust 專案。 Cargo 管理三件事:建置你的程式碼、下載你的程式碼所依賴的函式庫(libraries)、以及建置這些函式庫。 我們把這些你的程式所依賴的函式庫叫做「dependencies」,因為你的程式碼依賴他們。

最簡單的 Rust 程式不會有任何 dependencies,所以現在你只會用到第一部份的功能。 當你撰寫更複雜的 Rust 程式後,你將會希望加入 dependencies,如果你從 Cargo 開始的話,那就會簡單很多。

許多主要的 Rust 專案都使用 Cargo,我們假設在本書後面的章節你都會使用它。 如果你使用官方安裝檔,Cargo 將會隨著 Rust 一起裝好。 如果你用其他方法安裝 Rust,你可以輸入以下指令檢查是否已經裝好 Cargo:

$ cargo --version

在終端機內,如果你能看到版本號碼,那就太好了! 如果你看到錯誤訊息像是 command not found,則你應該要查閱你所安裝 Rust 的系統的相關文件,確定 Cargo 是否需要另外安裝。

轉換到 Cargo

讓我們開始轉換 Hello World 程式到 Cargo 上。 要將專案 Cargo 化的話,你需要做以下三件事:

  1. 把你的原始碼檔案放到正確的目錄。
  2. 去除舊的執行檔(在 Windows 是 main.exe,其他則是 main), 並另外建一個新的。
  3. 建立 Cargo 配置(configuration)檔。

讓我們開始吧!

建立新的執行檔和原始碼目錄

首先,回到終端機,移到 hello_world 目錄,輸入以下指令:

$ mkdir src
$ mv main.rs src/main.rs
$ rm main  # or 'del main.exe' on Windows

Cargo 預期原始碼會放在 src 目錄內,所以我們先弄好這部分。 最上層的專案目錄(在此為 hello_world)被保留來放置 README 檔、授權資訊、及其他與程式碼無關的東西。 這樣可以讓你保持專案的整潔。 物有所屬,所有東西都有自己的位置。

然後,複製 main.rssrc 目錄,然後刪除 rustc 所編譯出的檔案。 一如往常地, 在 Windows 下用 main.exe 取代 main

這個例子中保留 main.rs 作為原始碼檔名,是因為它可以建立執行檔。 如果你想要建立一個函式庫(library),你應該把檔案命名為 lib.rs。 Cargo 使用這樣的慣例去編譯專案,但如果你想要的話,你還是可以更改它。

建立配置檔

接著,在 hello_world 目錄下建立一個新的檔案,命名為 Cargo.toml

確保 Cargo.tomlC 是大寫,否則 Cargo 會無法處理這樣的配置檔。

這個檔案使用 TOML(Tom's Obvious, Minimal Language)格式。 TOML 跟 INI 很類似,但是有一些額外的好處,且被用來作為 Cargo 的配置格式。

在檔案內,輸入以下資訊:

[package]

name = "hello_world"
version = "0.0.1"
authors = [ "Your name <you@example.com>" ]

第一行,[package] 表示以下的陳述是用來配置一個套件(package)。 當我們要加入更多資訊到這個檔案內,我們會增加其他的小節(sections),但是現在,我們只有套件的配置。

其他三行設定了三項 Cargo 在編譯程式時所需知道的配置:程式的名字、版本、和作者。

Cargo.toml 檔案內加入這些資訊後,存檔然後結束。

建立並執行 Cargo 專案

Cargo.toml 檔案被放在專案的根目錄後,你應該就能建立並執行 Hello World 程式了! 輸入以下指令:

$ cargo build
   Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
$ ./target/debug/hello_world
Hello, world!

蹦!如果一切順利,Hello, world! 應該再次印在終端機上了。

你可以用 cargo build 建置專案、並透過 ./target/debug/hello_world 執行它,但你其實可以直接用 cargo run 一次就執行兩者:

$ cargo run
     Running `target/debug/hello_world`
Hello, world!

請注意,這個範例中並沒有重新建置專案。 Cargo 判斷檔案沒有更動,所以它直接去執行二進位執行檔。 如果你有修改原始碼,Cargo 就會在執行前重新建置專案,然後你會看到:

$ cargo run
   Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
     Running `target/debug/hello_world`
Hello, world!

Cargo 會檢查專案內的檔案是否有被更改,它只會在專案有更動的時候重新建置。

在簡單的專案中,Cargo 無法比 rustc 帶來更多好處,但是它在未來會越來越有用。 在用到許多 crates 的複雜專案中,使用 Cargo 去協調建置會比較簡單。 你只需要執行 cargo build,然後一切都會正確的運行。

建立發行版

當你的專案最終準備要發行時,你應該使用 cargo build --release 來最佳化編譯你的專案。 這些最佳化讓你的 Rust 程式碼執行得更快,但你的程式編譯起來會多花點時間。 這也是為什麼會有兩種不同的 profiles,其中一個用於開發,另一個用於建置最終給使用者的程式。

什麼是 Cargo.lock

執行 cargo build 也會讓 Cargo 建立一個叫做 Cargo.lock 的檔案,內容看起來像這樣:

[root]
name = "hello_world"
version = "0.0.1"

Cargo 使用 Cargo.lock 去追蹤應用程式的 dependencies。這是 Hello World 專案的 Cargo.lock 檔。 因為此專案沒有任何 dependencies,所以檔案有點稀疏。 實際上,你不需要自己去碰這個檔案;你只要讓 Cargo 去處理就好了。

就這樣!如果你一路照著做到現在,你應該已經成功地以 Cargo 建置 hello_world 了。

即使這個專案很簡單,它也使用到許多在你之後的 Rust 生涯中會真實用到的工具。 事實上,你能預期幾乎所有的 Rust 專案都會透過類似下述指令開始:

$ git clone someurl.com/foo
$ cd foo
$ cargo build

簡單地開始一個 Cargo 專案

當你想要開始一個新專案時,你不需要每次都重新執行一遍前面的所有流程! Cargo 可以快速的建立專案目錄骨架,然後你就可以開始開發。

用 Cargo 開始一個新專案,只要輸入 cargo new

$ cargo new hello_world --bin

這個指令傳遞了 --bin,因為它的目的是建立一個可執行的應用程式,而不是函式庫。 執行檔也常被稱作 二進位檔(binaries)。

Cargo 會產生兩個檔案和一個目錄給我們:Cargo.toml 檔案,src 目錄、和 src 下的 main.rs 檔案。 它們看起來與前面手動建立的結構很像。

這些就是我們全部所需的東西。 首先,打開 Cargo.toml。 它應該看起來像這樣:

[package]

name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]

Cargo 會根據你給它的參數和你的 git 環境配置產生帶有預設值的 Cargo.toml。 而你也能注意到 Cargo 同時會把 hello_world 目錄初始化成 git 的 repository。

至於 src/main.rs 內應該會長的像這樣:

fn main() {
    println!("Hello, world!");
}

Cargo 會幫你產生「Hello World!」程式碼,接著你就可以開始寫程式了!

註:如果你想要閱覽更多 Cargo 的細節,可以查閱官方的 Cargo 指南,其中包含有所有的功能。

結語

本章包含了在本書後述部分、及未來你的 Rust 時光的各種基礎。 現在你已經學會了工具,我們接著將更多地論及 Rust 本身。

你有兩個選擇:從 教學: 猜謎遊戲 深入一個專案,或從 語法及語意 由下而上開始。 有經驗的系統程式設計師可能會傾向從「教學: 猜謎遊戲」開始,而動態語言背景的人也許兩者都可以。 不同人有不同的學習方式! 請選擇適合自己的方式。

commit c3f6122