Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

函數回傳值

本集目標

讓函數回傳一個值,並學會 Rust 獨特的「不加分號就是回傳值」的寫法。

正文

上一集的函數只是把結果印出來。但很多時候我們想要的是:「你算完之後把答案交回來,我自己決定要怎麼用。」

基本語法

fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let result = add(3, 4);
    println!("3 + 4 = {}", result);
}

重點來了:

  1. -> i32 寫在參數後面,告訴 Rust「這個函數會回傳一個 i32
  2. 函數最後一行 a + b 沒有加分號 → 這就是回傳值

不加分號 = 回傳值

這是 Rust 最獨特的設計之一。函數最後一行如果不加分號,它的值就會自動被當成回傳值:

fn double(x: i32) -> i32 {
    x * 2 // ✅ 沒有分號,這就是回傳值
}

fn main() {}

加了分號會怎樣?

如果你不小心加了分號:

fn double(x: i32) -> i32 {
    x * 2; // ❌ 加了分號
}

fn main() {}

編譯器會報錯。為什麼?因為加了分號之後,x * 2 的計算結果會被丟掉,而函數最後沒有留下任何值。在這種狀況下,實際回傳的是 ()(unit type,還記得第 4 集嗎?)。但你答應了要回傳 i32,型別不符,編譯器就會抱怨。

沒寫回傳值的函數

回頭看本章第 6 集的 greet 函數,它沒有寫 -> 回傳值:

fn greet() {
    println!("你好!");
}

fn main() {}

在 Rust 裡,所有函數都有回傳值。沒寫 -> 的話,就等同於寫 -> ()

fn greet() -> () {
    println!("你好!");
}

fn main() {}

只是 -> () 通常省略不寫。println!("你好!"); 最後有分號,計算結果被丟掉,函數回傳 ()——剛好符合宣告。

接住回傳值

fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let result = add(3, 4);
    println!("結果:{}", result);

    // 也可以直接用在表達式裡
    println!("再加 10:{}", add(3, 4) + 10);
}

用 tuple 回傳多個值

函數只能回傳「一個」值,但如果你想回傳多個呢?把它們裝在 tuple 裡就好:

fn swap(a: i32, b: i32) -> (i32, i32) {
    (b, a)
}

fn main() {
    let result = swap(1, 2);
    println!("第一個:{},第二個:{}", result.0, result.1);
}

-> (i32, i32) 代表回傳一個包含兩個 i32 的 tuple。呼叫之後用 .0.1 取出裡面的值。

再來一個實用的例子:

fn min_max(a: i32, b: i32) -> (i32, i32) {
    if a < b {
        (a, b)
    } else {
        (b, a)
    }
}

fn main() {
    let result = min_max(7, 3);
    println!("最小:{},最大:{}", result.0, result.1);
}

重點整理

  • -> 型別 宣告函數的回傳型別
  • 函數最後一行不加分號,就是回傳值(這是 Rust 的慣用寫法)
  • 加了分號就變成普通語句,回傳的會是 ()
  • 沒寫回傳值的函數,其實回傳的是 ()
  • 想回傳多個值?用 tuple 包起來:-> (i32, i32),用 .0.1 取值