歡迎回到 Rust 的世界,我們今天來學 if 表達式。

上一篇:02_functions
本系列主頁面:Rust繁中簡學!
繁體中文版 Rustlings:https://github.com/TimLai666/rustlings-zh-TW
安裝方法:00_intro

03_if

If

if 是最基本(但仍然非常多用途!)的控制流類型,您將在這裡學習它。

進一步了解

單元的說明真是一次比一次簡潔😅

練習一(if1.rs

// if1.rs
//
// 執行 `rustlings hint if1` 或使用 `hint` watch 子命令來獲取提示。

// I AM NOT DONE

pub fn bigger(a: i32, b: i32) -> i32 {
    // 完成此函數以返回較大的數字!
    // 如果兩個數字相等,可以返回任意一個。
    // 不要使用:
    // - 其他函數調用
    // - 其他變數
}

// 暫時不用管這個 :)
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn ten_is_bigger_than_eight() {
        assert_eq!(10, bigger(10, 8));
    }

    #[test]
    fn fortytwo_is_bigger_than_thirtytwo() {
        assert_eq!(42, bigger(32, 42));
    }

    #[test]
    fn equal_numbers() {
        assert_eq!(42, bigger(42, 42));
    }
}
⚠️  編譯 exercises/03_if/if1.rs 失敗!請再試一次。以下是輸出:
error[E0308]: mismatched types
 --> exercises/03_if/if1.rs:7:34
  |
7 | pub fn bigger(a: i32, b: i32) -> i32 {
  |        ------                    ^^^ expected `i32`, found `()`
  |        |
  |        implicitly returns `()` as its body has no tail or `return` expression
  |
note: consider returning one of these bindings
 --> exercises/03_if/if1.rs:7:15
  |
7 | pub fn bigger(a: i32, b: i32) -> i32 {
  |               ^       ^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.

這題有個 bigger 函數,我們必須完成它,讓他回傳兩個數中比較大的數。

這個簡單,我們寫一個 if 來判斷 a 有沒有大於 b。如果有,就回傳 a,否則就回傳 b。

// if1.rs
//
// 執行 `rustlings hint if1` 或使用 `hint` watch 子命令來獲取提示。

// I AM NOT DONE

pub fn bigger(a: i32, b: i32) -> i32 {
    // 完成此函數以返回較大的數字!
    // 如果兩個數字相等,可以返回任意一個。
    // 不要使用:
    // - 其他函數調用
    // - 其他變數
    if a > b {
        return a;
    } else {
        return b;
    }
}

// 暫時不用管這個 :)
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn ten_is_bigger_than_eight() {
        assert_eq!(10, bigger(10, 8));
    }

    #[test]
    fn fortytwo_is_bigger_than_thirtytwo() {
        assert_eq!(42, bigger(32, 42));
    }

    #[test]
    fn equal_numbers() {
        assert_eq!(42, bigger(42, 42));
    }
}
進度: [########>---------------------------------------------------] 13/96 (13.5 %)               
✅  成功測試 exercises/03_if/if1.rs!

🎉 🎉 代碼正在編譯,並且測試通過! 🎉 🎉

您可以繼續進行此練習,
或通過刪除 `I AM NOT DONE` 註釋來進入下一個練習:

 3 |  // 執行 `rustlings hint if1` 或使用 `hint` watch 子命令來獲取提示。
 4 |  
 5 |  // I AM NOT DONE
 6 |  
 7 |  pub fn bigger(a: i32, b: i32) -> i32 {

第一題就這樣完成了。觀察程式碼可以發現,Rust 的 if 表達式的條件不需要加小括號。

練習二(if2.rs

// if2.rs
//
// 第一步:讓我編譯通過!
// 第二步:讓 bar_for_fuzz 和 default_to_baz 測試通過!
//
// 執行 `rustlings hint if2` 或使用 `hint` watch 子命令來獲取提示。

// I AM NOT DONE

pub fn foo_if_fizz(fizzish: &str) -> &str {
    if fizzish == "fizz" {
        "foo"
    } else {
        1
    }
}

// 不需要更改測試!
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn foo_for_fizz() {
        assert_eq!(foo_if_fizz("fizz"), "foo")
    }

    #[test]
    fn bar_for_fuzz() {
        assert_eq!(foo_if_fizz("fuzz"), "bar")
    }

    #[test]
    fn default_to_baz() {
        assert_eq!(foo_if_fizz("literally anything"), "baz")
    }
}
⚠️  編譯 exercises/03_if/if2.rs 失敗!請再試一次。以下是輸出:
error[E0308]: mismatched types
  --> exercises/03_if/if2.rs:14:9
   |
10 | pub fn foo_if_fizz(fizzish: &str) -> &str {
   |                                      ---- expected `&str` because of return type
...
14 |         1
   |         ^ expected `&str`, found integer

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.

這題的問題在於函數回傳值的資料型態和一開始將好的不同。

我們觀察一下程式碼,更改 if 表達式,讓程式依據不同情況回傳對應的字串。

// if2.rs
//
// 第一步:讓我編譯通過!
// 第二步:讓 bar_for_fuzz 和 default_to_baz 測試通過!
//
// 執行 `rustlings hint if2` 或使用 `hint` watch 子命令來獲取提示。

// I AM NOT DONE

pub fn foo_if_fizz(fizzish: &str) -> &str {
    if fizzish == "fizz" {
        "foo"
    } else if fizzish == "fuzz" {
        "bar"
    } else {
        "baz"
    }
}

// 不需要更改測試!
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn foo_for_fizz() {
        assert_eq!(foo_if_fizz("fizz"), "foo")
    }

    #[test]
    fn bar_for_fuzz() {
        assert_eq!(foo_if_fizz("fuzz"), "bar")
    }

    #[test]
    fn default_to_baz() {
        assert_eq!(foo_if_fizz("literally anything"), "baz")
    }
}

我們在 fizzish"fizz" 的時候回傳 "foo"fizzish"fuzz" 的時候回傳 "bar",其他時候則回傳 "baz"

進度: [########>---------------------------------------------------] 14/96 (14.6 %)               
✅  成功測試 exercises/03_if/if2.rs!

🎉 🎉 代碼正在編譯,並且測試通過! 🎉 🎉

您可以繼續進行此練習,
或通過刪除 `I AM NOT DONE` 註釋來進入下一個練習:

 6 |  // 執行 `rustlings hint if2` 或使用 `hint` watch 子命令來獲取提示。
 7 |  
 8 |  // I AM NOT DONE
 9 |  
10 |  pub fn foo_if_fizz(fizzish: &str) -> &str {

練習三(if3.rs

// if3.rs
//
// 執行 `rustlings hint if3` 或使用 `hint` watch 子命令來獲取提示。

// I AM NOT DONE

pub fn animal_habitat(animal: &str) -> &'static str {
    let identifier = if animal == "螃蟹" {
        1
    } else if animal == "地鼠" {
        2.0
    } else if animal == "蛇" {
        3
    } else {
        "未知"
    };

    // 請勿更改下面的這條語句
    let habitat = if identifier == 1 {
        "海灘"
    } else if identifier == 2 {
        "地洞"
    } else if identifier == 3 {
        "沙漠"
    } else {
        "未知"
    };

    habitat
}

// 不需要更改測試。
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn gopher_lives_in_burrow() {
        assert_eq!(animal_habitat("地鼠"), "地洞")
    }

    #[test]
    fn snake_lives_in_desert() {
        assert_eq!(animal_habitat("蛇"), "沙漠")
    }

    #[test]
    fn crab_lives_on_beach() {
        assert_eq!(animal_habitat("螃蟹"), "海灘")
    }

    #[test]
    fn unknown_animal() {
        assert_eq!(animal_habitat("恐龍"), "未知")
    }
}
⚠️  編譯 exercises/03_if/if3.rs 失敗!請再試一次。以下是輸出:
error[E0308]: `if` and `else` have incompatible types
  --> exercises/03_if/if3.rs:15:9
   |
12 |       } else if animal == "蛇" {
   |  ____________-
13 | |         3
   | |         - expected because of this
14 | |     } else {
15 | |         "未知"
   | |         ^^^^^^ expected integer, found `&str`
16 | |     };
   | |_____- `if` and `else` have incompatible types

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.

這題因為 if 表達式回傳的值不一致而出錯,包括 2.0 是浮點數,而 "未知" 是字串。我們把它們都改成整數即可。

// if3.rs
//
// 執行 `rustlings hint if3` 或使用 `hint` watch 子命令來獲取提示。

// I AM NOT DONE

pub fn animal_habitat(animal: &str) -> &'static str {
    let identifier = if animal == "螃蟹" {
        1
    } else if animal == "地鼠" {
        2
    } else if animal == "蛇" {
        3
    } else {
        0
    };

    // 請勿更改下面的這條語句
    let habitat = if identifier == 1 {
        "海灘"
    } else if identifier == 2 {
        "地洞"
    } else if identifier == 3 {
        "沙漠"
    } else {
        "未知"
    };

    habitat
}

// 不需要更改測試。
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn gopher_lives_in_burrow() {
        assert_eq!(animal_habitat("地鼠"), "地洞")
    }

    #[test]
    fn snake_lives_in_desert() {
        assert_eq!(animal_habitat("蛇"), "沙漠")
    }

    #[test]
    fn crab_lives_on_beach() {
        assert_eq!(animal_habitat("螃蟹"), "海灘")
    }

    #[test]
    fn unknown_animal() {
        assert_eq!(animal_habitat("恐龍"), "未知")
    }
}
進度: [#########>--------------------------------------------------] 15/96 (15.6 %)               
✅  成功測試 exercises/03_if/if3.rs!

🎉 🎉 代碼正在編譯,並且測試通過! 🎉 🎉

您可以繼續進行此練習,
或通過刪除 `I AM NOT DONE` 註釋來進入下一個練習:

 3 |  // 執行 `rustlings hint if3` 或使用 `hint` watch 子命令來獲取提示。
 4 |  
 5 |  // I AM NOT DONE
 6 |  
 7 |  pub fn animal_habitat(animal: &str) -> &'static str {

錯誤消失了,並且我們發現下列語法:

let identifier = if animal == "螃蟹" {
    1
} else if animal == "地鼠" {
    2
} else if animal == "蛇" {
    3
} else {
    0
};

Rust 的 if 表達式是可以接在變數宣告後面的,根據不同條件賦予變數不同的值,只不過它們的資料型態似乎必須一樣。

總結

if 表達式的練習結束了,重點摘要如下:

  1. Rust 的 if 表達式的條件不需要加小括號。
  2. Rust 的 if 表達式可以接在變數宣告後面,根據不同條件賦予變數不同的值。
  3. if 表達式的回傳值資料型態必須一致。

Similar Posts

One Comment

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *