rust:第十三章trait
目录
第十三章 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<T: Summary>(item: T) { println!("突发新闻!{}", item.summarize()); }
多个参数:
// impl Trait pub fn notify(item1: impl Summary, item2: impl Summary) { // item1和item2可以是不同类型 } // Trait Bound(强制相同类型) pub fn notify<T: Summary>(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<T>(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<T> { x: T, y: T, } impl<T> Pair<T> { fn new(x: T, y: T) -> Self { Self { x, y } } } impl<T: Display + PartialOrd> Pair<T> { 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<T>(Vec<T>); impl<T: Display> Display for Wrapper<T> { 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<T: Display> 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<Box<dyn Playable>>, } impl Playlist { pub fn new() -> Self { Playlist { items: Vec::new() } } pub fn add(&mut self, item: Box<dyn Playable>) { 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<T: Printable> Printable for Vec<T> { 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至关重要。
rust/第十三章trait.txt · 最后更改: 由 127.0.0.1
