Skip to content

Day 12: Trait系统

Trait是Rust定义共享行为的方式,类似于其他语言中的接口(interface)。它允许你指定某种类型必须实现哪些方法,从而实现多态和代码复用。

Rust的trait系统是其类型安全的核心,让我们能够:

  • 定义共享行为接口
  • 为现有类型添加新行为(blanket implementation)
  • 通过trait约束进行泛型编程

使用 trait 关键字定义trait,后面跟上方法签名:

trait Summary {
fn summarize(&self) -> String;
}
struct Article {
title: String,
author: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.title, self.author)
}
}
struct Tweet {
username: String,
content: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
fn main() {
let article = Article {
title: String::from("Rust语言教程"),
author: String::from("张三"),
content: String::from("这是一篇关于Rust的教程..."),
};
let tweet = Tweet {
username: String::from("@rustacean"),
content: String::from("学习Rust真有趣!"),
};
println!("文章摘要: {}", article.summarize());
println!("推文摘要: {}", tweet.summarize());
}

Trait可以提供方法的默认实现,这样实现者可以直接使用默认行为或选择重写:

trait Summary {
fn summarize(&self) -> String {
String::from("(阅读更多...)")
}
}
struct Article {
title: String,
author: String,
content: String,
}
// 使用默认实现
impl Summary for Article {}
struct Tweet {
username: String,
content: String,
}
// 重写默认实现
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.username, self.content)
}
}
fn main() {
let article = Article {
title: String::from("Rust语言教程"),
author: String::from("张三"),
content: String::from("这是一篇关于Rust的教程..."),
};
let tweet = Tweet {
username: String::from("@rustacean"),
content: String::from("学习Rust真有趣!"),
};
println!("文章摘要: {}", article.summarize());
println!("推文摘要: {}", tweet.summarize());
}

Trait约束(trait bound)允许我们限定泛型类型必须实现某个trait:

use std::fmt::Display;
trait Printable {
fn print(&self);
}
// 使用 trait bound 语法
fn print_all<T: Printable>(items: &[T]) {
for item in items {
item.print();
}
}
// 更简洁的语法:where子句
fn print_all_clean<T>(items: &[T])
where
T: Printable,
{
for item in items {
item.print();
}
}
// 多重约束
fn print_and_display<T: Printable + Display>(item: &T) {
item.print();
println!("{}", item);
}

Trait也可以直接作为函数参数类型,实现运行时多态:

trait Drawable {
fn draw(&self);
}
struct Circle {
radius: f64,
}
struct Rectangle {
width: f64,
height: f64,
}
impl Drawable for Circle {
fn draw(&self) {
println!("绘制圆,半径为 {}", self.radius);
}
}
impl Drawable for Rectangle {
fn draw(&self) {
println!("绘制矩形 {}x{}", self.width, self.height);
}
}
fn render(shape: &dyn Drawable) {
shape.draw();
}
fn main() {
let circle = Circle { radius: 5.0 };
let rect = Rectangle { width: 10.0, height: 20.0 };
render(&circle);
render(&rect);
}

注意 &dyn Drawable 语法,dyn 关键字表示这是一个动态分发(dynamic dispatch),在运行时确定具体类型。

Rust允许为满足某些条件的类型实现trait,这称为”blanket implementation”:

use std::fmt::Display;
trait PrintDisplay {
fn print_and_display(&self);
}
// 为所有实现 Display 的类型实现 PrintDisplay
impl<T: Display> PrintDisplay for T {
fn print_and_display(&self) {
println!("{}", self);
}
}
fn main() {
let num = 42;
num.print_and_display();
let text = "Hello, Rust";
text.print_and_display();
}

Trait可以继承其他trait,简化多重约束:

trait Printable: Clone + Debug {
fn print(&self);
}
#[derive(Clone, Debug)]
struct Book {
title: String,
pages: u32,
}
impl Printable for Book {
fn print(&self) {
println!("书名: {:?}, 页数: {:?}", self, self.pages);
}
}
fn main() {
let book = Book {
title: String::from("Rust编程"),
pages: 300,
};
book.print();
}

今天我们深入学习了Rust的trait系统:

  • Trait定义:使用 trait 关键字定义共享行为接口
  • 默认实现:trait方法可以提供默认实现,实现者可以选择重写
  • Trait约束:通过 <T: Trait> 或 where 子句限定泛型类型
  • 动态分发:&dyn Trait 允许运行时多态,但有轻微性能开销
  • Blanket Implementation:为满足条件的类型批量实现trait

Trait与泛型结合构成了Rust灵活而强大的类型系统。明天我们将学习Rust的集合类型,包括 Vec、HashMap 等常用数据结构。