Learn Rust Coding · 课时

where 子句与多重约束

让复杂的签名保持易读。

第 4 / 4 课13 个步骤

where 子句与多重约束 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。

内联约束变得拥挤时

随着约束增多,类似 <T: Display + Clone, U: Debug + Default> 的内联写法会变得难以阅读。Rust 提供了 where 子句作为更清晰的替代方案。

它会将约束移到签名下方,同时保持参数列表简洁。

基本 where 子句

where 子句位于返回类型和函数体之间。每一行列出一个类型及其约束。

这两个签名的含义完全相同;where 形式只是更易读。

use std::fmt::Display;

fn show<T>(value: T)
where
    T: Display,
{
    println!("{}", value);
}

where 中的多个约束

您可以为每个类型参数分别列出多个约束,并用逗号分隔。每个参数还可以使用 + 组合多个特征。

与把所有内容挤在一行内相比,这样即使签名复杂,也更易阅读。

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

fn report<T, U>(a: T, b: U)
where
    T: Display + Clone,
    U: Debug,
{
    println!("{} {:?}", a, b);
}

完整示例

这个程序使用要求实现 Display 的 where 子句。程序会运行,并为每个参数打印标签。

请注意,即使附加了约束,函数头仍然保持简洁。

use std::fmt::Display;

fn label<T>(name: &str, value: T)
where
    T: Display,
{
    println!("{} = {}", name, value);
}

fn main() {
    label("age", 30);
    label("city", "Oslo");
}

编译器无法内联的约束

有些约束只能写在 where 子句中,例如针对关联类型或引用类型的约束。内联语法无法表达 where Vec<T>: Clone。

因此,where 形式的表达能力严格更强。

fn duplicate<T>(items: Vec<T>) -> (Vec<T>, Vec<T>)
where
    Vec<T>: Clone,
{
    (items.clone(), items)
}

组合标准特征

现实中常见的约束会同时要求排序、复制和打印。这个泛型 max_of 可以在切片中找出最大元素。

where 子句将算法所依赖的三个特征集中列出。

use std::fmt::Display;

fn max_of<T>(items: &[T]) -> &T
where
    T: PartialOrd + Display,
{
    let mut best = &items[0];
    for item in items {
        if item > best { best = item; }
    }
    best
}

运行 max_of

下面是同一思路的可运行程序。整数切片满足 PartialOrd + Display,因此调用可以通过编译并打印最大值。

这个函数同样适用于浮点数或字符。

fn max_of<T>(items: &[T]) -> &T
where
    T: PartialOrd,
{
    let mut best = &items[0];
    for item in items {
        if item > best { best = item; }
    }
    best
}

fn main() {
    let nums = [3, 7, 1, 9, 4];
    println!("{}", max_of(&nums));
}

impl 块中的 where

where 子句也可以附加到 impl 块上。只有存储的类型实现了 Display 时,才会添加这个方法。

其中 T 不是 Display 的实例,将不会拥有这个方法。

use std::fmt::Display;

struct Holder<T> { item: T }

impl<T> Holder<T>
where
    T: Display,
{
    fn print(&self) {
        println!("{}", self.item);
    }
}

同时使用多个约束

实际的泛型 API 往往要求每个参数实现多个特征。这个签名要求类型支持克隆、调试和默认值。

即使一个类型有三个约束,where 子句也能让代码保持易读。

use std::fmt::Debug;

fn build<T>() -> T
where
    T: Default + Clone + Debug,
{
    let v = T::default();
    v.clone()
}

选择内联约束还是 where

只有一两个简单约束时,请使用内联约束。当参数较多、特征列表较长,或约束涉及复杂类型时,请改用 where。

两种写法会编译成完全相同的代码;选择哪一种只关系到可读性。

where 与生命周期

where 子句可以在列出特征约束的同时,列出生存期之间的关系。这样可以有条理地组织同时包含这两类约束的泛型签名。

这里的子句要求 T 的存活时间长于生命周期 'a。

fn keep<'a, T>(value: &'a T) -> &'a T
where
    T: 'a,
{
    value
}

快速检查

检验您对 where 子句和多个约束的理解。

回顾

where 子句会将特征约束移到签名下方;当参数或特征列表变长时,这能提高可读性。它还可以表达内联语法无法表达的复杂类型约束和生命周期约束。

内联约束和 where 约束编译结果完全相同,因此请选择可读性更好的写法。

免费开始

用 AI 导师学习 Rust — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
39
课程
144

常见问题解答

「where 子句与多重约束」课时是免费的吗?

是的 — 「where 子句与多重约束」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。

「where 子句与多重约束」这节课中我会学到什么?

让复杂的签名保持易读。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「where 子句与多重约束」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 泛型函数
  2. 泛型结构体和枚举
  3. 特征约束
  4. where 子句与多重约束
← 返回 Learn Rust Coding