學習軌道
/
Rust
Rust
/
練習
/
盧西恩的美味千層麵
盧西恩的美味千層麵

盧西恩的美味千層麵

學習練習

簡介

在 Rust 中,把值指定給一個名稱稱為_綁定_。除非用mut關鍵字宣告,否則綁定都是不可變的。由於 Rust 是靜態型別的語言,每個綁定都有一個在編譯期就知道的型別。

綁定最常使用let關鍵字定義。對大多數綁定來說,指定型別是選填的,因為 Rust 的_型別推論_通常可以根據值推斷出型別。一個綁定看起來像這樣:

// Automatically inferred type
let fingers = 10;

函式是_項目_。綁定通常指向某個特定的值,而項目指的是程式碼組織的單位,通常是一個函式或一個模組,它在程式的整個生命週期內都可以使用。函式會自動回傳最後一個運算式的結果。函式可以有 0 個或多個參數,這些參數是生命週期僅限於該次函式呼叫的綁定。

理論上函式也能做型別推論,但 Rust 刻意在語言設計上關閉了這個功能。這表示寫程式時,你得花多一點時間明確指定函式的輸入與輸出型別;但讀程式碼時就省下了時間,因為所有輸入與輸出型別都已經明確寫出來了。

fn add(x: i32, y: i32) -> i32 {
  x + y
}

呼叫函式的方式,是寫出函式名稱,後面接著括號。如果函式需要參數,就必須在括號內為每個參數指定一個引數。

let five = add(2, 3);

如果無法推斷綁定的型別,編譯器會回報錯誤。要修正這個問題,請為該綁定加上明確的型別標註。

// Explicit type annotation
let fingers: i32 = 10;

Rust 的項目在定義之前或之後都可以使用,因為它們有靜態生命週期。相較之下,綁定只能在定義_之後_使用。在綁定定義之前就使用它,會導致編譯錯誤。

fn main() {
    // `fn add` hasn't yet been defined, but that's perfectly ok
    dbg!(add(3, 4));
}

fn add(x: i32, y: i32) -> i32 {
  x + y
}
// this won't compile; `a` is used before its binding is defined
let b = a;
let a = x + y;

Rust 使用大括號({})來定義作用域。在作用域內定義的綁定無法脫離這個作用域。

let a = 1;
dbg!(a); // 1
{
    // Here, we re-bind `a` to a new value, which is still immutable.
    // This technique is called _shadowing_. The new binding is constrained to
    // this anonymous scope. Outside this scope, the previous binding still
    // applies.
    let a = 2;
    let b = 3;
    dbg!(a, b); // 2, 3
}
// can't use `b` anymore because it is out of scope
// dbg!(b);

// The shadowed `a` in the inner scope above has fallen out of scope,
// leaving us with our original binding.
dbg!(a); // 1

Rust 的項目通常會用模組來組織。每個 crate 本身隱含就是一個模組,但它可以定義任意深度的內部子模組。模組會把相關的功能群組在一起,並使用mod關鍵字定義。

mod calc_i32 {
    fn add(a: i32, b: i32) -> i32 { a + b }
    fn sub(a: i32, b: i32) -> i32 { a - b }
    fn mul(a: i32, b: i32) -> i32 { a * b }
    fn div(a: i32, b: i32) -> i32 { a / b }
}

Rust 支援兩種註解。//這個關鍵字代表單行註解;從它之後到行尾的所有內容都會被忽略。/*和*/這兩個關鍵字代表多行註解;在這兩個關鍵字之間的所有內容都會被忽略。偏好使用單行註解是符合慣例的好做法。

Rust 也支援文件註解,它們會出現在cargo doc產生的文件中。外層文件註解使用///關鍵字撰寫,行為和//關鍵字完全相同。它們會套用在後面接著的項目上,例如函式:

/// The `add` function produces the sum of its arguments.
fn add(x: i32, y: i32) -> i32 { x + y }

內層文件註解使用//!關鍵字撰寫,行為和//關鍵字完全相同。它們會套用在包住它們的項目上,例如模組:

mod my_cool_module {
    //! This module is the bee's knees.
}

文件註解可以是任意長度,並且可以包含 Markdown,這些內容會算繪進產生的文件裡。

說明

在這個練習中,你會寫一些程式碼,幫助自己照著最愛的食譜書烤出超美味的千層麵。

你有四個任務,全都和烹調千層麵所花的時間有關。

1. 定義預期的烤箱時間(以分鐘為單位)

定義expected_minutes_in_oven綁定,用來確認千層麵應該在烤箱中烤幾分鐘。根據食譜書,預期的烤箱時間是 40 分鐘:

expected_minutes_in_oven()
// Returns: 40

2. 計算剩餘的烤箱時間(以分鐘為單位)

定義remaining_minutes_in_oven函式,它接受千層麵已經在烤箱中實際烤過的分鐘數作為參數,並根據上一個任務算出的預期烤箱時間,回傳千層麵還需要在烤箱中待幾分鐘。

remaining_minutes_in_oven(30)
// Returns: 10

3. 計算準備時間(以分鐘為單位)

定義preparation_time_in_minutes函式,它接受你加到千層麵裡的層數作為參數,並回傳你準備千層麵所花的分鐘數,假設每一層需要 2 分鐘來準備。

preparation_time_in_minutes(2)
// Returns: 4

4. 計算經過的時間(以分鐘為單位)

定義elapsed_time_in_minutes函式,它接受兩個參數:第一個參數是你加到千層麵裡的層數,第二個參數是千層麵已經在烤箱中的分鐘數。這個函式應該回傳你烹調千層麵所花的分鐘數,也就是準備時間(分鐘)加上千層麵目前在烤箱中已經待的分鐘數。

elapsed_time_in_minutes(3, 20)
// Returns: 26
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Rust Exercism

準備好開始 盧西恩的美味千層麵 了嗎?

註冊 Exercism,透過 99 個練習 和真人引導來學習並精通 Rust,全部免費。