强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第11章:Trait 系统

第11章:Trait 系统

11.1 什么是 Trait

Trait 定义了类型必须实现的行为(方法签名),类似其他语言的接口(interface)。

定义与实现

// 定义 trait
trait Drawable {
    fn draw(&self);
    fn area(&self) -> f64;
}

struct Circle {
    radius: f64,
}

struct Square {
    side: f64,
}

// 为 Circle 实现 trait
impl Drawable for Circle {
    fn draw(&self) {
        println!("画一个半径为 {} 的圆", self.radius);
    }

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

// 为 Square 实现 trait
impl Drawable for Square {
    fn draw(&self) {
        println!("画一个边长为 {} 的正方形", self.side);
    }

    fn area(&self) -> f64 {
        self.side * self.side
    }
}

fn main() {
    let shapes: Vec<Box<dyn Drawable>> = vec![
        Box::new(Circle { radius: 5.0 }),
        Box::new(Square { side: 4.0 }),
    ];

    for shape in &shapes {
        shape.draw();
        println!("面积: {:.2}\n", shape.area());
    }
}

11.2 默认实现

trait Greeting {
    fn name(&self) -> &str;

    // 默认实现(可被覆盖)
    fn hello(&self) -> String {
        format!("你好,我是 {}", self.name())
    }

    fn goodbye(&self) -> String {
        format!("{} 说再见", self.name())
    }
}

struct Person {
    name: String,
}

impl Greeting for Person {
    fn name(&self) -> &str {
        &self.name
    }
    // hello 和 goodbye 使用默认实现
}

struct Robot {
    id: u32,
}

impl Greeting for Robot {
    fn name(&self) -> &str {
        "机器人"
    }

    // 覆盖默认实现
    fn hello(&self) -> String {
        format!("[系统{}] 初始化完毕", self.id)
    }
}

fn main() {
    let person = Person { name: "张三".to_string() };
    let robot = Robot { id: 42 };

    println!("{}", person.hello());    // 你好,我是 张三
    println!("{}", person.goodbye());  // 张三 说再见
    println!("{}", robot.hello());     // [系统42] 初始化完毕
    println!("{}", robot.goodbye());   // 机器人 说再见
}

11.3 Trait 作为参数

impl Trait 语法

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

struct Article {
    title: String,
    content: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}: {}", self.title, &self.content[..50.min(self.content.len())])
    }
}

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

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

// impl Trait 语法(语法糖)
fn notify(item: &impl Summary) {
    println!("新消息: {}", item.summarize());
}

// Trait bound 语法(等价写法)
fn notify_bound<T: Summary>(item: &T) {
    println!("新消息: {}", item.summarize());
}

fn main() {
    let article = Article {
        title: "Rust 发布新版本".to_string(),
        content: "Rust 2024 edition 带来了许多新特性...".to_string(),
    };

    let tweet = Tweet {
        username: "rustlang".to_string(),
        text: "Rust is awesome!".to_string(),
    };

    notify(&article);
    notify(&tweet);
}

多个 Trait 约束

use std::fmt::{Debug, Display};

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

fn display_and_summary<T: Display + Summary>(item: &T) {
    println!("Display: {}", item);
    println!("Summary: {}", item.summarize());
}

// where 子句(更清晰)
fn complex_function<T, U>(t: &T, u: &U) -> String
where
    T: Display + Clone,
    U: Debug + Summary,
{
    format!("t={}, u={:?}", t, u)
}

11.4 Trait 作为返回类型

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

struct Article {
    title: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("文章: {}", self.title)
    }
}

struct Tweet {
    text: String,
}

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

// 返回 impl Trait(静态分发,编译时确定具体类型)
fn create_summary(kind: &str) -> impl Summary {
    Article {
        title: format!("关于{}的文章", kind),
    }
}

// 如果需要根据条件返回不同类型,需要 Box<dyn Trait>
fn create_summary_dynamic(kind: &str) -> Box<dyn Summary> {
    if kind == "article" {
        Box::new(Article { title: "文章标题".to_string() })
    } else {
        Box::new(Tweet { text: "推文内容".to_string() })
    }
}

fn main() {
    let s1 = create_summary("Rust");
    println!("{}", s1.summarize());

    let s2 = create_summary_dynamic("article");
    let s3 = create_summary_dynamic("tweet");
    println!("{}", s2.summarize());
    println!("{}", s3.summarize());
}

11.5 静态分发与动态分发

特性静态分发 (impl Trait / 泛型)动态分发 (dyn Trait)
确定时间编译时运行时
性能零开销(单态化)间接调用(vtable)
二进制大小较大(代码膨胀)较小
异构集合❌ 不支持✅ 支持
内联优化✅ 可以❌ 不能
trait Animal {
    fn sound(&self) -> &str;
}

struct Dog;
struct Cat;

impl Animal for Dog {
    fn sound(&self) -> &str { "汪汪" }
}

impl Animal for Cat {
    fn sound(&self) -> &str { "喵喵" }
}

// 静态分发:编译器为每种类型生成专用版本
fn print_sound_static(animal: &impl Animal) {
    println!("静态: {}", animal.sound());
}

// 动态分发:通过 vtable 进行间接调用
fn print_sound_dynamic(animal: &dyn Animal) {
    println!("动态: {}", animal.sound());
}

fn main() {
    let dog = Dog;
    let cat = Cat;

    // 静态分发
    print_sound_static(&dog);
    print_sound_static(&cat);

    // 动态分发
    print_sound_dynamic(&dog);
    print_sound_dynamic(&cat);

    // 异构集合需要动态分发
    let animals: Vec<Box<dyn Animal>> = vec![
        Box::new(Dog),
        Box::new(Cat),
    ];

    for animal in &animals {
        println!("{}", animal.sound());
    }
}

11.6 常用标准库 Trait

Trait说明派生
Debug调试格式化 {:?}#[derive(Debug)]
Display用户友好格式化 {}手动实现
Clone深拷贝 .clone()#[derive(Clone)]
Copy位拷贝(栈上类型)#[derive(Copy, Clone)]
PartialEq相等比较 ==#[derive(PartialEq)]
Eq完全相等(浮点不可用)#[derive(Eq, PartialEq)]
PartialOrd部分排序 <, >#[derive(PartialOrd)]
Ord完全排序 .sort()#[derive(Ord, PartialOrd)]
Hash哈希计算#[derive(Hash)]
Default默认值#[derive(Default)]
From/Into类型转换手动实现 From
Iterator迭代器手动实现

Display 实现

use std::fmt;

struct Color {
    r: u8,
    g: u8,
    b: u8,
}

impl fmt::Display for Color {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "#{:02X}{:02X}{:02X}", self.r, self.g, self.b)
    }
}

impl fmt::Debug for Color {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Color({}, {}, {})", self.r, self.g, self.b)
    }
}

fn main() {
    let red = Color { r: 255, g: 0, b: 0 };
    println!("Display: {}", red);  // #FF0000
    println!("Debug:   {:?}", red); // Color(255, 0, 0)
}

From/Into 转换

#[derive(Debug)]
struct Celsius(f64);

#[derive(Debug)]
struct Fahrenheit(f64);

impl From<Celsius> for Fahrenheit {
    fn from(c: Celsius) -> Self {
        Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
    }
}

impl From<Fahrenheit> for Celsius {
    fn from(f: Fahrenheit) -> Self {
        Celsius((f.0 - 32.0) * 5.0 / 9.0)
    }
}

fn main() {
    let boiling = Celsius(100.0);
    let f: Fahrenheit = boiling.into();
    println!("{:?} = {:?}", Celsius(100.0), f);

    let body = Fahrenheit(98.6);
    let c: Celsius = body.into();
    println!("{:?} = {:?}", Fahrenheit(98.6), c);
}

11.7 Trait 继承

trait Base {
    fn base_method(&self);
}

trait Extended: Base {
    fn extended_method(&self);
}

struct MyType;

impl Base for MyType {
    fn base_method(&self) {
        println!("基础方法");
    }
}

impl Extended for MyType {
    fn extended_method(&self) {
        println!("扩展方法");
        self.base_method(); // 可以调用父 trait 的方法
    }
}

fn main() {
    let obj = MyType;
    obj.extended_method();
}

11.8 业务场景示例

序列化框架

trait Serializable {
    fn serialize(&self) -> String;
    fn content_type(&self) -> &str;
}

trait Deserializable: Sized {
    fn deserialize(data: &str) -> Result<Self, String>;
}

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

impl Serializable for User {
    fn serialize(&self) -> String {
        format!("name={},email={},age={}", self.name, self.email, self.age)
    }

    fn content_type(&self) -> &str {
        "text/plain"
    }
}

impl Deserializable for User {
    fn deserialize(data: &str) -> Result<Self, String> {
        let mut name = String::new();
        let mut email = String::new();
        let mut age = 0;

        for pair in data.split(',') {
            let parts: Vec<&str> = pair.splitn(2, '=').collect();
            match parts[0] {
                "name" => name = parts[1].to_string(),
                "email" => email = parts[1].to_string(),
                "age" => age = parts[1].parse().map_err(|e| format!("{}", e))?,
                _ => {}
            }
        }

        Ok(User { name, email, age })
    }
}

fn transfer<T: Serializable>(item: &T) -> String {
    println!("Content-Type: {}", item.content_type());
    item.serialize()
}

fn main() {
    let user = User {
        name: "Alice".to_string(),
        email: "[email protected]".to_string(),
        age: 30,
    };

    let data = transfer(&user);
    println!("序列化: {}", data);

    let user2 = User::deserialize(&data).unwrap();
    println!("反序列化: {:?}", user2);
}

插件系统

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

struct UpperCasePlugin;
struct ReversePlugin;
struct CountPlugin;

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() }
}

impl Plugin for CountPlugin {
    fn name(&self) -> &str { "Count" }
    fn version(&self) -> &str { "1.0.0" }
    fn execute(&self, input: &str) -> String {
        format!("{} ({}字符)", input, input.chars().count())
    }
}

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

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

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

    fn process(&self, input: &str) -> String {
        let mut result = input.to_string();
        for plugin in &self.plugins {
            result = plugin.execute(&result);
        }
        result
    }
}

fn main() {
    let mut manager = PluginManager::new();
    manager.register(Box::new(UpperCasePlugin));
    manager.register(Box::new(ReversePlugin));
    manager.register(Box::new(CountPlugin));

    let result = manager.process("hello world");
    println!("最终结果: {}", result);
}

11.9 本章小结

要点说明
Trait 定义定义类型必须实现的行为
默认实现trait 方法可以提供默认实现
impl Trait语法糖,用于参数和返回值
Trait boundT: Trait 形式的泛型约束
静态分发编译时确定,零开销
动态分发运行时通过 vtable 调用
常用 TraitDebug、Display、Clone、Copy、From 等

扩展阅读

  1. Rust Book - Trait — 官方教程
  2. Rust Reference - Traits — 语言参考
  3. dyn Trait vs impl Trait — trait 对象详解