1. 多重 Trait Bound
有時候希望泛型同時滿足多個 trait,可以用 +。
use std::fmt::Display;
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
title: String,
author: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
fn print_info<T: Display + Summary>(item: &T) {
println!("Info: {}", item.summarize());
println!("Display: {}", item);
}
fn main() {
let a = Article {
title: String::from("Rust News"),
author: String::from("Alice"),
};
print_info(&a);
}
這裡 T 必須同時實作 Display 和 Summary。
2. where 語法
如果 trait bound 很多,寫在函數簽名會變得很長,可以用 where 簡化。
use std::fmt::Display;
fn notify<T, U>(t: &T, u: &U)
where
T: Display + Summary,
U: Display,
{
println!("t: {}, {}", t, t.summarize());
println!("u: {}", u);
}
3. 回傳實作 Trait 的型別
函數也可以回傳某個實作了 trait 的型別,用 impl Trait。
trait Summary {
fn summarize(&self) -> String;
}
struct News(String);
impl Summary for News {
fn summarize(&self) -> String {
format!("News: {}", self.0)
}
}
fn get_news() -> impl Summary {
News(String::from("Rust 2.0 released"))
}
fn main() {
let n = get_news();
println!("{}", n.summarize());
}
輸出:
News: Rust 2.0 released
4. Trait Bound 與 Option / Result
fn double<T: std::ops::Add<Output = T>>(x: T, y: T) -> T {
x + y
}
fn main() {
println!("{}", double(3, 4));
println!("{}", double(1.5, 2.5));
}
輸出:
7
4.0
這裡 <T: Add<Output = T>> 限制 T 必須支援加法運算。
5. 學習心得與補充
今天學到多重 trait bound 和 where 語法,讓我感受到 Rust 在表達限制上的靈活度。以前在 C++ 用 template 時,常常不知道一個泛型型別到底能不能做加法,錯誤訊息也很難懂,Rust 則是透過 trait bound 讓我清楚知道泛型需要什麼能力,編譯器也能在一開始就檢查。我覺得特別方便的是 impl Trait,可以直接讓函數回傳一個符合某個行為的東西,而不用暴露具體型別。這讓我回想到前幾天學到的 Option 和 Result,它們其實就是泛型搭配 trait 的實際應用。雖然語法有點長,但學會 where 之後就讓程式碼更容易閱讀。整體來說,今天的內容讓我更理解 Rust 如何用 trait 和泛型把型別和行為結合在一起。