20·面向对象进阶

Trait 特征

Trait 特征

学习目标

  1. 定义和实现 trait
  2. 理解默认实现
  3. 掌握 trait 作为参数
  4. 理解孤儿规则

核心概念

定义 Trait

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

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

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}, 作者 {}", 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("Alice"),
        content: String::from("..."),
    };
    println!("{}", article.summarize());
}

默认实现

trait Summary {
    fn summarize(&self) -> String {
        String::from("(阅读更多...)")
    }
}

struct EmptyArticle;

impl Summary for EmptyArticle {}  // 使用默认实现

fn main() {
    let a = EmptyArticle;
    println!("{}", a.summarize());  // "(阅读更多...)"
}

Trait 作为参数

// 方式一:impl Trait 语法
fn notify(item: &impl Summary) {
    println!("速报: {}", item.summarize());
}

// 方式二:Trait Bound 语法
fn notify<T: Summary>(item: &T) {
    println!("速报: {}", item.summarize());
}

// 多个 trait 约束
fn notify(item: &(impl Summary + std::fmt::Display)) { }

fn notify<T: Summary + std::fmt::Display>(item: &T) { }

返回 impl Trait

fn create_summarizable() -> impl Summary {
    Tweet {
        username: String::from("rust"),
        content: String::from("Rust 1.0 发布!"),
    }
}

Trait 对象(动态分发)

trait Animal {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;

impl Animal for Dog {
    fn speak(&self) -> String { String::from("汪汪") }
}

impl Animal for Cat {
    fn speak(&self) -> String { String::from("喵喵") }
}

fn main() {
    // Trait 对象:dyn Trait
    let animals: Vec<Box<dyn Animal>> = vec![
        Box::new(Dog),
        Box::new(Cat),
        Box::new(Dog),
    ];

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

孤儿规则

// ✅ 可以为自己的类型实现自己的 trait
trait MyTrait { }
struct MyType;
impl MyTrait for MyType { }

// ✅ 可以为自己的类型实现标准库的 trait
impl std::fmt::Display for MyType {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "MyType")
    }
}

// ❌ 不能为外部类型实现外部 trait
// impl Vec<i32> for String { }

常用标准库 Trait

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

// Display 需要手动实现
impl std::fmt::Display for Point {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    let p = Point { x: 1, y: 2 };
    println!("{}", p);       // Display
    println!("{:?}", p);     // Debug
    let p2 = p.clone();      // Clone
    assert_eq!(p, p2);       // PartialEq
}

实践练习

练习 1:可打印

trait Printable {
    fn print(&self);
    fn format(&self) -> String;
}

impl Printable for i32 {
    fn print(&self) { println!("{}", self); }
    fn format(&self) -> String { format!("i32: {}", self) }
}

impl Printable for String {
    fn print(&self) { println!("{}", self); }
    fn format(&self) -> String { format!("String: \"{}\"", self) }
}

fn print_all(items: &[&dyn Printable]) {
    for item in items {
        item.print();
    }
}

fn main() {
    let items: Vec<&dyn Printable> = vec![&42, &String::from("hello")];
    print_all(&items);
}

练习 2:可比较

trait MaxValue {
    fn max_value() -> Self;
}

impl MaxValue for i32 {
    fn max_value() -> Self { i32::MAX }
}

impl MaxValue for f64 {
    fn max_value() -> Self { f64::MAX }
}

fn main() {
    println!("i32 max: {}", i32::max_value());
    println!("f64 max: {}", f64::max_value());
}

常见错误

1. 未实现所有方法

trait MyTrait {
    fn a();
    fn b();
}

struct Foo;
// impl MyTrait for Foo {
//     fn a() {}  // ❌ 缺少 b
// }

2. 孤儿规则违反

// ❌ 不能为 Vec 实现 Display(都是外部的)
// impl std::fmt::Display for Vec<i32> { }

小结

概念说明
trait定义共享行为
impl Trait for Type为类型实现 trait
impl Trait参数/返回值的 trait 约束
dyn Traittrait 对象(动态分发)
孤儿规则至少一个类型是本地的
#[derive(...)]自动派生常用 trait

练习编辑器

rust
Loading...