where 子句与多重约束
让复杂的签名保持易读。
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 反馈 — 无需本地设置。