跳到主要内容

Trait(特征)

Trait(特征)是 Rust 中定义共享行为的方式。它类似于其他语言中的接口(interface),但更加强大和灵活。

定义 Trait

基本 Trait 定义

trait Summary {
fn summarize(&self) -> String;
}

struct NewsArticle {
headline: String,
location: String,
author: String,
content: String,
}

impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}

struct Tweet {
username: String,
content: String,
reply: bool,
retweet: bool,
}

impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}

fn main() {
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 new tweet: {}", tweet.summarize());
}

默认实现

trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}

fn summarize_author(&self) -> String;

fn summarize_with_author(&self) -> String {
format!("(Read more from {}...)", self.summarize_author())
}
}

struct NewsArticle {
headline: String,
location: String,
author: String,
content: String,
}

impl Summary for NewsArticle {
fn summarize_author(&self) -> String {
format!("@{}", self.author)
}

// 可以选择重写默认实现
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}

fn main() {
let article = NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from("The Pittsburgh Penguins once again are the best hockey team in the NHL."),
};

println!("New article available! {}", article.summarize());
println!("Author info: {}", article.summarize_with_author());
}

Trait 作为参数

impl Trait 语法

trait Summary {
fn summarize(&self) -> String;
}

struct NewsArticle {
headline: String,
author: String,
}

impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {}", self.headline, self.author)
}
}

fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}

// 等价的 trait bound 语法
fn notify_bound<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}

fn main() {
let article = NewsArticle {
headline: String::from("Rust 1.70 Released!"),
author: String::from("Rust Team"),
};

notify(&article);
notify_bound(&article);
}

多个 Trait Bound

trait Summary {
fn summarize(&self) -> String;
}

trait Display {
fn fmt(&self) -> String;
}

struct NewsArticle {
headline: String,
author: String,
}

impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {}", self.headline, self.author)
}
}

impl Display for NewsArticle {
fn fmt(&self) -> String {
format!("Article: {}", self.headline)
}
}

// 多个 trait bound
fn notify(item: &(impl Summary + Display)) {
println!("Breaking news! {}", item.summarize());
println!("Display: {}", item.fmt());
}

// 使用 where 子句更清晰
fn notify_where<T>(item: &T)
where
T: Summary + Display,
{
println!("Breaking news! {}", item.summarize());
println!("Display: {}", item.fmt());
}

fn main() {
let article = NewsArticle {
headline: String::from("Rust 1.70 Released!"),
author: String::from("Rust Team"),
};

notify(&article);
}

返回 Trait

trait Summary {
fn summarize(&self) -> String;
}

struct NewsArticle {
headline: String,
author: String,
}

struct Tweet {
username: String,
content: String,
}

impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {}", self.headline, self.author)
}
}

impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}

fn returns_summarizable() -> impl Summary {
NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
author: String::from("Iceburgh"),
}
}

// 注意:不能根据条件返回不同类型
// fn returns_summarizable(switch: bool) -> impl Summary {
// if switch {
// NewsArticle { ... } // 错误!
// } else {
// Tweet { ... } // 错误!
// }
// }

fn main() {
let article = returns_summarizable();
println!("Article: {}", article.summarize());
}

常用的标准库 Trait

Clone 和 Copy

#[derive(Debug, Clone)]
struct Point {
x: i32,
y: i32,
}

#[derive(Debug, Clone, Copy)]
struct SimplePoint {
x: i32,
y: i32,
}

fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = p1.clone(); // 显式克隆
println!("p1: {:?}, p2: {:?}", p1, p2);

let sp1 = SimplePoint { x: 1, y: 2 };
let sp2 = sp1; // Copy trait 允许隐式复制
println!("sp1: {:?}, sp2: {:?}", sp1, sp2); // sp1 仍然有效
}

PartialEq 和 Eq

#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: u32,
}

fn main() {
let person1 = Person {
name: "Alice".to_string(),
age: 30,
};

let person2 = Person {
name: "Alice".to_string(),
age: 30,
};

println!("相等: {}", person1 == person2);
}

PartialOrd 和 Ord

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Person {
name: String,
age: u32,
}

fn main() {
let mut people = vec![
Person { name: "Bob".to_string(), age: 25 },
Person { name: "Alice".to_string(), age: 30 },
Person { name: "Charlie".to_string(), age: 20 },
];

people.sort();
println!("排序后: {:?}", people);
}

Display 和 Debug

use std::fmt;

struct Point {
x: i32,
y: i32,
}

impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}

impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Point")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}

fn main() {
let point = Point { x: 1, y: 2 };
println!("Display: {}", point);
println!("Debug: {:?}", point);
}

关联类型

trait Iterator {
type Item; // 关联类型

fn next(&mut self) -> Option<Self::Item>;
}

struct Counter {
current: usize,
max: usize,
}

impl Counter {
fn new(max: usize) -> Counter {
Counter { current: 0, max }
}
}

impl Iterator for Counter {
type Item = usize;

fn next(&mut self) -> Option<Self::Item> {
if self.current < self.max {
let current = self.current;
self.current += 1;
Some(current)
} else {
None
}
}
}

fn main() {
let mut counter = Counter::new(5);

while let Some(value) = counter.next() {
println!("Value: {}", value);
}
}

Trait 对象

动态分发

trait Draw {
fn draw(&self);
}

struct Circle {
radius: f64,
}

struct Rectangle {
width: f64,
height: f64,
}

impl Draw for Circle {
fn draw(&self) {
println!("Drawing a circle with radius {}", self.radius);
}
}

impl Draw for Rectangle {
fn draw(&self) {
println!("Drawing a rectangle {}x{}", self.width, self.height);
}
}

fn main() {
let shapes: Vec<Box<dyn Draw>> = vec![
Box::new(Circle { radius: 5.0 }),
Box::new(Rectangle { width: 10.0, height: 20.0 }),
];

for shape in shapes {
shape.draw();
}
}

对象安全

// 对象安全的 trait
trait Draw {
fn draw(&self);
}

// 不是对象安全的 trait(有泛型方法)
trait Clone {
fn clone<T>(&self) -> T; // 错误:泛型方法
}

// 不是对象安全的 trait(返回 Self)
trait Clone2 {
fn clone(&self) -> Self; // 错误:返回 Self
}

// 对象安全的版本
trait Drawable {
fn draw(&self);
fn area(&self) -> f64;
}

struct Circle {
radius: f64,
}

impl Drawable for Circle {
fn draw(&self) {
println!("Drawing circle");
}

fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}

fn main() {
let circle: Box<dyn Drawable> = Box::new(Circle { radius: 5.0 });
circle.draw();
println!("Area: {}", circle.area());
}

高级 Trait 特性

运算符重载

use std::ops::Add;

#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
x: i32,
y: i32,
}

impl Add for Point {
type Output = Point;

fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}

fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 3, y: 4 };
let p3 = p1 + p2;

println!("{:?} + {:?} = {:?}", p1, p2, p3);
}

完全限定语法

trait Pilot {
fn fly(&self);
}

trait Wizard {
fn fly(&self);
}

struct Human;

impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.");
}
}

impl Wizard for Human {
fn fly(&self) {
println!("Up!");
}
}

impl Human {
fn fly(&self) {
println!("*waving arms furiously*");
}
}

fn main() {
let person = Human;

person.fly(); // 调用 Human 的方法
Pilot::fly(&person); // 调用 Pilot trait 的方法
Wizard::fly(&person); // 调用 Wizard trait 的方法

// 完全限定语法
<Human as Pilot>::fly(&person);
}

关联函数的完全限定语法

trait Animal {
fn baby_name() -> String;
}

struct Dog;

impl Dog {
fn baby_name() -> String {
String::from("puppy")
}
}

impl Animal for Dog {
fn baby_name() -> String {
String::from("Spot")
}
}

fn main() {
println!("A baby dog is called a {}", Dog::baby_name());
println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}

Supertraits

use std::fmt;

trait OutlinePrint: fmt::Display {
fn outline_print(&self) {
let output = self.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("*{}*", " ".repeat(len + 2));
println!("* {} *", output);
println!("*{}*", " ".repeat(len + 2));
println!("{}", "*".repeat(len + 4));
}
}

struct Point {
x: i32,
y: i32,
}

impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}

impl OutlinePrint for Point {}

fn main() {
let point = Point { x: 1, y: 3 };
point.outline_print();
}

实际应用示例

插件系统

trait Plugin {
fn name(&self) -> &str;
fn version(&self) -> &str;
fn execute(&self, input: &str) -> String;
}

struct UppercasePlugin;
struct ReversePlugin;

impl Plugin for UppercasePlugin {
fn name(&self) -> &str {
"Uppercase"
}

fn version(&self) -> &str {
"1.0.0"
}

fn execute(&self, input: &str) -> String {
input.to_uppercase()
}
}

impl Plugin for ReversePlugin {
fn name(&self) -> &str {
"Reverse"
}

fn version(&self) -> &str {
"1.0.0"
}

fn execute(&self, input: &str) -> String {
input.chars().rev().collect()
}
}

struct PluginManager {
plugins: Vec<Box<dyn Plugin>>,
}

impl PluginManager {
fn new() -> Self {
PluginManager {
plugins: Vec::new(),
}
}

fn register(&mut self, plugin: Box<dyn Plugin>) {
println!("Registered plugin: {} v{}", plugin.name(), plugin.version());
self.plugins.push(plugin);
}

fn execute_all(&self, input: &str) -> Vec<String> {
self.plugins
.iter()
.map(|plugin| {
let result = plugin.execute(input);
println!("{} -> {}", plugin.name(), result);
result
})
.collect()
}
}

fn main() {
let mut manager = PluginManager::new();

manager.register(Box::new(UppercasePlugin));
manager.register(Box::new(ReversePlugin));

let results = manager.execute_all("Hello World");
println!("Results: {:?}", results);
}

最佳实践

  1. 优先使用 trait bound 而不是 trait 对象:除非需要动态分发
  2. 合理使用默认实现:减少重复代码
  3. 保持 trait 简洁:单一职责原则
  4. 使用关联类型:当 trait 与特定类型紧密相关时
  5. 考虑对象安全性:如果需要 trait 对象
// 好的 trait 设计示例
trait Serialize {
type Output;
type Error;

fn serialize(&self) -> Result<Self::Output, Self::Error>;
}

trait Deserialize<T> {
type Error;

fn deserialize(input: T) -> Result<Self, Self::Error>
where
Self: Sized;
}

#[derive(Debug)]
struct JsonError(String);

struct Person {
name: String,
age: u32,
}

impl Serialize for Person {
type Output = String;
type Error = JsonError;

fn serialize(&self) -> Result<Self::Output, Self::Error> {
Ok(format!(r#"{{"name":"{}","age":{}}}"#, self.name, self.age))
}
}

impl Deserialize<&str> for Person {
type Error = JsonError;

fn deserialize(input: &str) -> Result<Self, Self::Error> {
// 简化的 JSON 解析
if input.contains("name") && input.contains("age") {
Ok(Person {
name: "Parsed".to_string(),
age: 25,
})
} else {
Err(JsonError("Invalid JSON".to_string()))
}
}
}

fn main() {
let person = Person {
name: "Alice".to_string(),
age: 30,
};

match person.serialize() {
Ok(json) => {
println!("Serialized: {}", json);

match Person::deserialize(&json) {
Ok(parsed) => println!("Parsed: {:?}", parsed),
Err(e) => println!("Parse error: {:?}", e),
}
}
Err(e) => println!("Serialize error: {:?}", e),
}
}

Trait 是 Rust 中实现抽象和多态的核心机制,通过合理使用 trait 可以编写出灵活、可扩展的代码。