====== 第十三章 Trait ====== ===== 13.1 什么是Trait ===== Trait定义了类型可以共享的行为。类似于其他语言中的接口(interface),但功能更强大。 **Trait的作用:** * 定义共享的行为 * 实现泛型编程 * 提供抽象接口 ===== 13.2 定义和实现Trait ===== ==== 定义Trait ==== pub trait Summary { fn summarize(&self) -> String; } ==== 实现Trait ==== pub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String, } impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}, by {} ({})", self.headline, self.author, self.location) } } pub struct Tweet { pub username: String, pub content: String, pub reply: bool, pub retweet: bool, } impl Summary for Tweet { fn summarize(&self) -> String { format!("{}: {}", self.username, self.content) } } ==== 使用Trait ==== let tweet = Tweet { username: String::from("horse_ebooks"), content: String::from("of course, as you probably already know, people"), reply: false, retweet: false, }; println!("1条新推文:{}", tweet.summarize()); ===== 13.3 默认实现 ===== Trait可以提供默认实现: pub trait Summary { fn summarize(&self) -> String { String::from("(Read more...)") } } impl Summary for NewsArticle {} // 使用默认实现 impl Summary for Tweet { fn summarize(&self) -> String { format!("{}: {}", self.username, self.content) } } **默认实现可以调用其他方法:** pub trait Summary { fn summarize_author(&self) -> String; fn summarize(&self) -> String { format!("(Read more from {}...)", self.summarize_author()) } } impl Summary for Tweet { fn summarize_author(&self) -> String { format!("@{}", self.username) } } ===== 13.4 Trait作为参数 ===== ==== impl Trait语法 ==== pub fn notify(item: impl Summary) { println!("突发新闻!{}", item.summarize()); } ==== Trait Bound语法 ==== pub fn notify(item: T) { println!("突发新闻!{}", item.summarize()); } **多个参数:** // impl Trait pub fn notify(item1: impl Summary, item2: impl Summary) { // item1和item2可以是不同类型 } // Trait Bound(强制相同类型) pub fn notify(item1: T, item2: T) { // item1和item2必须是相同类型 } ===== 13.5 多个Trait Bound ==== ==== 使用+语法 ==== use std::fmt::Display; pub fn notify(item: impl Summary + Display) { println!("突发新闻!{}", item.summarize()); } // 或使用where子句 pub fn notify(item: T) where T: Summary + Display, { println!("突发新闻!{}", item.summarize()); } ===== 13.6 返回实现Trait的类型 ==== fn returns_summarizable() -> impl Summary { Tweet { username: String::from("horse_ebooks"), content: String::from("of course, as you probably already know, people"), reply: false, retweet: false, } } **限制:** 只能返回单一具体类型 // 错误!不能返回不同类型的impl Trait fn returns_summarizable(switch: bool) -> impl Summary { if switch { NewsArticle { headline: String::from("..."), location: String::from("..."), author: String::from("..."), content: String::from("..."), } } else { Tweet { username: String::from("..."), content: String::from("..."), reply: false, retweet: false, } } } ===== 13.7 使用Trait Bound有条件地实现方法 ===== use std::fmt::Display; struct Pair { x: T, y: T, } impl Pair { fn new(x: T, y: T) -> Self { Self { x, y } } } impl Pair { fn cmp_display(&self) { if self.x >= self.y { println!("最大的成员是 x = {}", self.x); } else { println!("最大的成员是 y = {}", self.y); } } } ===== 13.8 使用Trait Bound有条件地实现Trait ===== use std::fmt::Display; struct Wrapper(Vec); impl Display for Wrapper { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[")?; for (i, v) in self.0.iter().enumerate() { if i > 0 { write!(f, ", ")?; } write!(f, "{}", v)?; } write!(f, "]") } } **为任何实现了Display的类型实现ToString:** impl ToString for T { // ... } 这称为** blanket implementations**(全覆盖实现)。 ===== 13.9 常用标准库Trait ===== ==== Debug ==== #[derive(Debug)] struct Point { x: i32, y: i32, } ==== PartialEq和Eq ==== #[derive(PartialEq, Eq)] struct Point { x: i32, y: i32, } ==== PartialOrd和Ord ==== #[derive(PartialEq, Eq, PartialOrd, Ord)] struct Point { x: i32, y: i32, } ==== Clone和Copy ==== #[derive(Clone, Copy)] struct Point { x: i32, y: i32, } ==== Default ==== #[derive(Default)] struct Config { debug: bool, timeout: u32, } let config = Config::default(); ===== 13.10 完整示例:媒体播放器 ===== // 定义Playable trait pub trait Playable { fn play(&self); fn pause(&self) { println!("Paused"); } fn stop(&self); } // 定义音频 pub struct Audio { title: String, artist: String, } impl Audio { pub fn new(title: &str, artist: &str) -> Self { Audio { title: title.to_string(), artist: artist.to_string(), } } } impl Playable for Audio { fn play(&self) { println!("Playing audio: {} by {}", self.title, self.artist); } fn stop(&self) { println!("Stopped audio: {}", self.title); } } // 定义视频 pub struct Video { title: String, resolution: (u32, u32), } impl Video { pub fn new(title: &str, width: u32, height: u32) -> Self { Video { title: title.to_string(), resolution: (width, height), } } } impl Playable for Video { fn play(&self) { println!("Playing video: {} at {}x{}", self.title, self.resolution.0, self.resolution.1); } fn pause(&self) { println!("Video paused at {}x{}", self.resolution.0, self.resolution.1); } fn stop(&self) { println!("Stopped video: {}", self.title); } } // 播放列表 pub struct Playlist { items: Vec>, } impl Playlist { pub fn new() -> Self { Playlist { items: Vec::new() } } pub fn add(&mut self, item: Box) { self.items.push(item); } pub fn play_all(&self) { for item in &self.items { item.play(); } } } fn main() { let mut playlist = Playlist::new(); playlist.add(Box::new(Audio::new("Song", "Artist"))); playlist.add(Box::new(Video::new("Movie", 1920, 1080))); playlist.play_all(); } ===== 练习题 ===== ==== 练习题13.1:实现Comparable trait ==== trait Comparable { fn compare(&self, other: &Self) -> i32; } struct Rectangle { width: u32, height: u32, } impl Comparable for Rectangle { fn compare(&self, other: &Self) -> i32 { let area1 = self.width * self.height; let area2 = other.width * other.height; if area1 > area2 { 1 } else if area1 < area2 { -1 } else { 0 } } } fn main() { let r1 = Rectangle { width: 10, height: 20 }; let r2 = Rectangle { width: 5, height: 30 }; match r1.compare(&r2) { 1 => println!("r1更大"), -1 => println!("r2更大"), _ => println!("一样大"), } } ==== 练习题13.2:实现Printable trait ==== trait Printable { fn print(&self); } impl Printable for i32 { fn print(&self) { println!("整数:{}", self); } } impl Printable for String { fn print(&self) { println!("字符串:{}", self); } } impl Printable for Vec { fn print(&self) { println!("向量:["); for item in self { print!(" "); item.print(); } println!("]"); } } fn main() { let numbers = vec![1, 2, 3]; numbers.print(); } ===== 本章小结 ===== 本章学习了Rust的Trait系统: * **定义Trait**:trait关键字定义共享行为 * **实现Trait**:impl Trait for Type * **默认实现**:提供默认方法体 * **Trait作为参数**:impl Trait或T: Trait * **Trait Bound**:约束泛型类型 * **条件实现**:基于Trait Bound实现方法和Trait Trait是Rust实现多态和代码复用的核心机制,理解Trait对于掌握Rust至关重要。