====== 第十三章 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至关重要。