Menu
CoddyTech

Trait 约束语法

本课属于 Coddy Rust 学习旅程的“面向对象编程”单元。第 40 课,共 61 课。

到目前为止,你已经学会了定义特征并为结构体实现它们。你还使用泛型编写了灵活的代码。现在该把这些概念结合起来了:使用特征来限制泛型函数可以接受的类型。

考虑一个通用函数,它需要在参数上调用特定方法。如果没有任何约束,Rust 无法保证类型 T 具有该方法:

fn print_info<T>(item: T) {
    println!("{}", item.summarize());  // 错误!T 可能没有 summarize() 方法
}

解决办法是使用trait 约束。在泛型参数后添加 : TraitName,即可告诉 Rust,T 必须实现该 trait:

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

fn print_info<T: Summary>(item: T) {
    println!("{}", item.summarize());  // 现在 Rust 知道这个方法存在了
}

语法 <T: Summary> 表示“T 是任何实现了 Summary 的类型”。现在,这个函数只接受具有所需行为的类型。如果你尝试传入未实现 Summary 的类型,编译器会拒绝它,并给出明确的错误提示。

这种模式很强大,因为它让你能够编写通用代码,同时仍然可以使用特定功能。你的函数保持灵活,适用于任何类型,但只有提供所需行为的类型才能使用。

challenge icon

挑战

简单

让我们构建一个通知系统,使用 trait 约束确保只能发送格式正确的消息!你将创建一个泛型函数,它接受任何实现了特定 trait 的类型,以此展示 trait 约束如何限制泛型参数。

你将把代码分成两个文件:

  • notification.rs:定义一个公开的 Notify trait,其中包含一个名为 message 的方法,该方法接受 &self 并返回一个 String。然后创建两个实现了这个 trait 的公开结构体:
    • Email:包含一个公开的 subject 字段(String)。它的 message 方法应返回 Email: {subject}
    • SMS:包含一个公开的 content 字段(String)。它的 message 方法应返回 SMS: {content}
    最后,创建一个名为 send_notification 的公开泛型函数,它接受任何实现了 Notify trait 的类型 T。这个函数应打印对该项调用 message() 的结果。
  • main.rs:引入通知模块,并使用提供的输入分别创建一个 Email 实例和一个 SMS 实例。分别对它们调用 send_notification,以证明你的泛型函数适用于任何实现了 Notify 的类型。

这里的关键点是,send_notification 不知道它接收的具体类型是什么。它只知道该类型能够生成一条消息。trait 约束 T: Notify 保证了这一能力。

你的输出应显示发送了这两条通知:

Email: {subject}
SMS: {content}

例如,输入 Meeting Tomorrow 和 On my way! 时:

Email: Meeting Tomorrow
SMS: On my way!

你将收到两个输入:邮件主题和 SMS 内容。

亲手试试

mod notification;

use notification::{Email, SMS, send_notification};

fn main() {
    // 读取输入
    let mut subject = String::new();
    std::io::stdin().read_line(&mut subject).expect("Failed to read line");
    let subject = subject.trim().to_string();
    
    let mut content = String::new();
    std::io::stdin().read_line(&mut content).expect("Failed to read line");
    let content = content.trim().to_string();
    
    // TODO: 使用 subject 创建一个 Email 实例
    
    // TODO: 使用 content 创建一个 SMS 实例
    
    // TODO: 将 email 传给 send_notification 并调用它
    
    // TODO: 将 sms 传给 send_notification 并调用它
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Rust 在线编译器