8.2 默认泛型类型参数
听
Rust 允许在定义泛型结构体、枚举或 trait 时,为类型参数指定默认值。这一特性称为默认泛型类型参数(Default Generic Type Parameters),它在保持接口灵活性的同时,简化了常见用法的调用,并支持在不破坏现有代码的前提下扩展 API。
基本语法
使用 = Type 语法为泛型参数提供默认值:
struct Point<T = f64> {
x: T,
y: T,
}
现在,Point 可以在不显式指定类型的情况下使用:
let p1 = Point { x: 1.0, y: 2.0 }; // T 推断为 f64(默认)
let p2 = Point::<i32> { x: 1, y: 2 }; // 显式指定 T 为 i32
若字段类型不同,则仍需显式指定(或使用其他设计):
// 错误:x 和 y 必须是同一类型
// let p = Point { x: 1, y: 2.0 };
在 trait 中使用默认泛型参数
默认泛型参数在 trait 中尤其有用,可用于向后兼容地扩展功能。
标准库中的 Add trait 就是一个典型例子:
trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
这里,Rhs(Right-hand side)默认为 Self,因此 a + b 在 a 和 b 类型相同时无需额外标注。但也可以实现 Add<i32> for MyType 来支持不同类型加法。
例如,为 Point<f64> 实现与标量的加法:
impl Add<f64> for Point<f64> {
type Output = Point<f64>;
fn add(self, rhs: f64) -> Self::Output {
Point {
x: self.x + rhs,
y: self.y + rhs,
}
}
}
向后兼容的 API 演进
假设你发布了一个库,最初定义了一个泛型结构体:
struct Container<T> {
data: Vec<T>,
}
后来你希望添加一个可选的自定义比较器(用于排序等操作),但又不想让现有用户修改代码。可以引入默认泛型参数:
struct Container<T, C = std::cmp::Ordering> {
data: Vec<T>,
comparator: C,
}
但更合理的做法是让比较器本身有默认实现,例如:
use std::cmp::Ordering;
#[derive(Default)]
struct DefaultComparator;
struct Container<T, C = DefaultComparator> {
data: Vec<T>,
cmp: C,
}
这样,旧代码 Container::<i32> 仍然有效,而新用户可以选择传入自定义比较器类型。
注意事项
- 默认值只在省略类型参数时生效,一旦显式指定任何泛型参数,其余未指定的仍需提供或也使用默认;
- 多个泛型参数可各自设置默认值:
struct Example<A = i32, B = String, C = ()> { /* ... */ } - 默认类型必须在定义处可见,且不能引用其他未确定的泛型参数(如
struct S<T, U = T>是不允许的)。
小结
默认泛型类型参数是一种优雅的 API 设计工具。它减少了用户在常见场景下的样板代码,同时保留了高级用法的灵活性。结合关联类型和 trait bounds,它使 Rust 的泛型系统既能表达复杂的抽象,又能保持简洁易用。在开发可扩展的库时,合理使用默认泛型参数,有助于构建平滑演进的公共接口。
#Rust 入门教程
分享于 1 周前
上一篇:8.1 关联类型
下一篇:8.3 完全限定语法