cargo

rustc 的意思是 Rust 編譯器,實際的編譯工作由它完成。Rust 檔案是用 .rs 作結尾。但大多數人不會去寫類似 rustc main.rs 的東西來編譯。他們使用的是名為 cargo 的東西,它是 Rust 的主要套件管理器。

關於這個名字的說明:之所以叫 cargo,是因為當你把板條箱 (crate) 放在一起時,你會得到貨物 (cargo)。Crate 就是你在貨船或卡車上見到的木箱,但你會記得,每個 Rust 專案也叫 Crate。那麼當你把它們放在一起時,你就會得到一整個 Cargo。

當你使用 Cargo 來執行專案時,你可以見到這一點。讓我們用 rand 來試試簡單的東西:我們只會隨機在八個字母之間選擇。

use rand::seq::SliceRandom; // 讓 .choose 能使用在 slices 上

fn main() {

    let my_letters = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];

    let mut rng = rand::thread_rng();
    for _ in 0..6 {
        print!("{} ", my_letters.choose(&mut rng).unwrap());
    }
}

會印出 b **c** g h e a 這樣的東西。但我們想先看看 cargo 的作用。要使用 cargo 來執行我們的程式,通常我們按鍵輸入 cargo run。這樣就可以組建我們的程式,並為我們執行。當它開始編譯時,會做這樣的事情:

   Compiling getrandom v0.1.14
   Compiling cfg-if v0.1.10
   Compiling ppv-lite86 v0.2.8
   Compiling rand_core v0.5.1
   Compiling rand_chacha v0.2.2
   Compiling rand v0.7.3
   Compiling rust_book v0.1.0 (C:\Users\mithr\OneDrive\Documents\Rust\rust_book)
    Finished dev [unoptimized + debuginfo] target(s) in 13.13s
     Running `C:\Users\mithr\OneDrive\Documents\Rust\rust_book\target\debug\rust_book.exe`
g f c f h b

所以看起來不只引進了 rand,還有一些其它的也是。這是因為我們的 crate 需要 rand,而 rand 也有一些程式碼也需要其它 crate。所以 cargo 會找到我們需要的所有 crate,並把它們放在一起。在我們的案例中,我們只有七個,但在非常大的專案中,你可能會有 200 個或更多的 crate 要引進。

這就是你可以看到 Rust 的權衡妥協的地方。Rust 的速度極快,因為它提前編譯。它透過檢視程式碼,看你寫的程式碼到底做了什麼。例如,你可能會寫這樣的泛型程式碼:

use std::fmt::Display;

fn print_and_return_thing<T: Display>(input: T) -> T {
    println!("You gave me {} and now I will give it back.", input);
    input
}

fn main() {
    let my_name = print_and_return_thing("Windy");
    let small_number = print_and_return_thing(9.0);
}

這個函式可以接受實作 Display 的任何型別作為引數,所以我們給它 &str,接下來給它 f64,這對我們來說沒什麼問題。但是編譯器不看泛型,因為它不想在執行時期做任何事情。它想把能執行的程式儘可能快地組裝起來。所以當它看第一部分的 "Windy" 時,它不是看到 fn print_and_return_thing<T: Display>(input: T) -> T,它看到的是 fn print_and_return_thing(input: &str) -> &str 這樣的東西。而接下來它看到的是 fn print_and_return_thing(input: f64) -> f64。所有關於特徵的檢查等等都是在編譯時期完成的。這就是為什麼泛型需要更長的時間來編譯,因為它需要弄清楚它們,並使之具體化。

還有一件事:Rust 2020 正在努力處理編譯時間問題,因為這部分需要的時間最長。每個版本的 Rust 在編譯時都會快一點,而且還有一些其他的計劃來加快它的速度。但與此同時,這裡是你該知道的:

  • cargo build 會組建你的程式,這樣你就可以執行它了。
  • cargo run 將組建你的程式並且執行。
  • cargo build --releasecargo run --release 有同樣的效果,不過是在釋出模式 (Release mode) 下。那是什麼?釋出模式是用在當你的程式碼終於完成的時候。然後 Rust 會花更多的時間來編譯,但它這樣做是因為它使用了它所知道的一切,來使編譯出的程式執行得更快。釋出模式實際上比被稱為除錯模式 (Debug mode) 的常規模式執行時還 快的多。那是因為常規模式的編譯速度更快,而且有更多的除錯資訊。常規的 cargo build 叫做 "debug build",cargo build --release 叫做 "release build"。
  • cargo check 是一種檢查程式碼的方式。它就像編譯一樣,除了它並不會真正地做出你的程式。這是經常檢查你的程式碼的好方式,因為它不像 buildrun 那樣需要花很長時間。

對了,命令中的 --release 這部分叫做 flag。這意味著命令裡帶有額外的資訊。

一些其他你需要知道的事情:

  • cargo new 這麼做是為了建立新的 Rust 專案。在 new 之後寫上專案名稱,cargo 將會做出所有你需要的檔案和資料夾。
  • cargo clean 當你把 crate 新增到 Cargo.toml 時,電腦會下載所有需要的檔案,並且會佔用很多空間。如果你不想再讓它們留在你的電腦上,可以輸入 cargo clean

關於編譯器還有一件事:只有當你第一次使用 cargo buildcargo run 時,它才會花費最多的時間。在那之後它就會記得一些資訊,又會快速的編譯了。但如果你使用 cargo clean,然後執行 cargo build,它將不得不再慢慢地編譯一次。