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

turbofish 語法

本集目標

學會用 ::<> turbofish 語法手動指定型別參數,理解它和泛型定義的關係。

概念說明

前幾集我們學了泛型——函數、structenum 都可以有型別參數 <T>。大部分時候 Rust 能自動推斷 T 是什麼,但有時候編譯器推不出來,就需要我們手動告訴它。

turbofish 是什麼?

還記得第一章學 parse 的時候,我們寫過這樣的程式碼嗎?

fn main() {
    let input = "1";
    let num = input.trim().parse::<i32>().expect("請輸入數字");
}

當時我們把 ::<i32> 當黑盒子照抄。現在學了泛型,終於可以理解它了!

.parse() 是一個泛型方法,有一個型別參數 T,代表「你想把字串轉成什麼型別」。但光看 input.trim().parse() 這段程式碼,編譯器不知道你想轉成 i32 還是 f64 還是其他東西。

所以我們用 ::<i32> 手動指定 T = i32。這個 ::<> 語法就叫做 turbofish(因為 ::<> 看起來像一條魚 🐟)。

turbofish 的本質

turbofish 就是「手動填入泛型定義裡角括號的型別參數」:

  • 泛型定義:fn parse<T>(...)——這裡的 <T> 是宣告
  • turbofish:.parse::<i32>()——這裡的 ::<i32> 是填入

函數、方法、型別都可以用 turbofish:

// 函數的 turbofish
func::<i32>(arg);

// 型別的 turbofish
Vec::<i32>::new();

.parse() 做了什麼?

順便完整解釋一下 parse:它把字串轉換成你指定的型別。轉換可能失敗(比如 "abc" 不能轉成數字),所以需要搭配 .expect() 處理失敗的情況——這點在第一章就用過了。

範例程式碼

fn first<T>(a: T, _b: T) -> T {
    a
}

fn main() {
    // 通常 Rust 能自動推斷,不需要 turbofish
    let x = first(10, 20);
    println!("{}", x);

    // 手動用 turbofish 指定型別
    let y = first::<f64>(3.14, 2.71);
    println!("{}", y);

    // Vec 的 turbofish
    let v = Vec::<i32>::new();
    println!("{:?}", v);

    // parse 的 turbofish——呼應第一章的黑盒子
    let input = "42";
    let num = input.parse::<i32>().expect("不是數字");
    println!("{}", num);

    let pi = "3.14".parse::<f64>().expect("不是數字");
    println!("{}", pi);
}

重點整理

  • turbofish ::<> 是手動指定泛型型別參數的語法
  • 大部分時候 Rust 能自動推斷,不需要 turbofish
  • 當編譯器推不出型別時(例如 .parse()),就需要用 turbofish 手動指定
  • 第一章寫的 .parse::<i32>() 其實就是 turbofish——現在我們理解它為什麼這樣寫了
  • .parse() 把字串轉成指定型別,轉換可能失敗所以搭配 .expect() 使用