1. 什麼是 Trait
它定義了一組方法簽名(method signatures),型別只要實作 (implement) 這些方法,就能被當作該 trait 使用。
Trait 常常搭配泛型使用,用來限制型別必須擁有哪些行為。
2. 定義與實作 Trait
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 main() {
let a = Article {
title: String::from("Rust News"),
author: String::from("Alice"),
};
println!("{}", a.summarize());
}
輸出:
Rust News by Alice
3. Trait 作為參數
可以讓函數參數要求一個實作了某個 trait 的型別。
fn notify(item: &impl Summary) {
println!("Breaking news: {}", item.summarize());
}
這樣任何實作了 Summary trait 的型別都能傳入。
4. Trait Bound 與泛型
更完整的寫法是用 Trait Bound:
fn notify<T: Summary>(item: &T) {
println!("News: {}", item.summarize());
}//<T: Summary> 限制了 T 必須實作 Summary。
5. 預設方法
trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
struct Article {
title: String,
}
impl Summary for Article {} // 使用預設實作
fn main() {
let a = Article {
title: String::from("Rust News"),
};
println!("{}", a.summarize());
}
輸出:
(Read more...)
6. 學習心得與補充
今天學到的 Trait 讓我覺得它就像是行為的合約。只要一個型別實作了某個 trait,就能保證擁有那些方法。這和昨天學的泛型結合起來,讓我能指定這個泛型必須能比較大小或這個泛型必須能印出來。這樣設計不只避免錯誤,也讓程式碼更彈性。我覺得 trait 的概念和 C++ 的介面有點像,但 Rust 的語法更直接,還能有預設實作,使用起來更方便。