Menu
CoddyTech

where 子句

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

添加更多 trait 约束后,函数签名可能会变得难以阅读。考虑一个包含多个泛型参数的函数,其中每个参数都需要实现多个 trait:

fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
    // ...
}

这样可行,但函数签名变得越来越拥挤。where 子句提供了一种更简洁的替代方式,可以将 trait 限定移到参数列表之后:

fn complex_operation<T, U>(first: T, second: U)
where
    T: Display + Clone,
    U: Debug + Summary,
{
    // ...
}

这两个版本的功能完全相同:where 子句只是为了提高可读性。每种类型的要求都单独占一行,方便你快速查看每个泛型参数需要满足什么条件。

当约束复杂或泛型参数较多时,where 子句会特别有用。它能让函数名和参数一目了然,并将约束单独列在下方。当约束不止简单的 T: Trait 时,这是大多数 Rust 代码库首选的写法。

challenge icon

挑战

简单

让我们构建一个数据处理系统,使用 where 子句让复杂的 trait 限定保持清晰易读!你将创建一个带有多个类型参数的泛型函数,每个参数都需要实现不同的 trait,并使用 where 语法整齐地组织这些限定。

你将在两个文件中组织代码:

  • processor.rs:定义两个公开的 trait,以及一个同时使用它们的泛型函数:
    • Summarize:一个包含 summary 方法的 trait,该方法接收 &self 并返回 String
    • Validate:一个包含 validate 方法的 trait,该方法接收 &self 并返回 bool
    然后创建一个名为 process_items 的公开泛型函数,接收两个不同泛型类型的参数。使用 where 子句指定第一个类型必须同时实现 Clone 和 Summarize,第二个类型必须实现 Validate。函数应打印第一个项目的摘要,然后打印第二个项目是否有效。
  • main.rs:创建两个实现所需 trait 的公开结构体:
    • Article:包含一个公开的 title 字段(String)。实现 Summarize,使其返回 Article: {title},并派生 Clone。
    • Form:包含一个公开的 filled 字段(bool)。实现 Validate,使其返回 filled 的值。
    使用提供的输入创建一个 Article 和一个 Form,然后使用它们调用 process_items。

where 子句让函数签名比把所有限定都塞进尖括号中清晰得多。每种类型的要求都单独列出,方便你查看每个泛型参数需要满足什么条件。

输出应先显示摘要,然后显示验证结果:

Article: {title}
Valid: {true/false}

例如,输入 Rust Tips 和 true 时:

Article: Rust Tips
Valid: true

输入 Breaking News 和 false 时:

Article: Breaking News
Valid: false

你将收到两个输入:文章标题,以及表单是否已填写(解析为 bool)。

亲手试试

mod processor;

use processor::{Summarize, Validate, process_items};
use std::io;

// TODO: 定义一个公开的结构体 Article,包含公开的 title 字段(String)
// 为 Article 派生 Clone

// TODO: 为 Article 实现 Summarize
// summary 方法应返回 "Article: {title}"

// TODO: 定义一个公开的结构体 Form,包含公开的 filled 字段(bool)

// TODO: 为 Form 实现 Validate
// validate 方法应返回 filled 的值

fn main() {
    let mut title = String::new();
    io::stdin().read_line(&mut title).expect("Failed to read line");
    let title = title.trim().to_string();

    let mut filled_input = String::new();
    io::stdin().read_line(&mut filled_input).expect("Failed to read line");
    let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");

    // TODO: 使用给定的 title 创建一个 Article
    
    // TODO: 使用给定的 filled 值创建一个 Form
    
    // TODO: 将 article 和 form 传给 process_items
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Rust 在线编译器