Rust从入门到实战系列二百二十七:默认泛型类型参数和运算符重载

当使用泛型类型参数时,可以为泛型指定一个默认的具体类型。如果默认类型就足够的话,这
消除了为具体类型实现 trait 的需要。为泛型类型指定默认类型的语法是在声明泛型类型时使用
<PlaceholderType=ConcreteType>。
这种情况的一个非常好的例子是用于运算符重载。运算符重载(Operator overloading)是指在特定情况
下自定义运算符(比如 +)行为的操作。
Rust 并不允许创建自定义运算符或重载任意运算符,不过 std:: ops 中所列出的运算符和相应的 trait 可
以通过实现运算符相关 trait 来重载。例如,示例 19-14 中展示了如何在 Point 结构体上实现 Add trait
来重载 + 运算符,这样就可以将两个 Point 实例相加了:
文件名: src∕main.rs
use std::ops::Add;
#[derive(Debug, Copy, Clone, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
fn main() {
assert_eq!(
Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
Point { x: 3, y: 3 }
);
}
示例 19-14: 实现 Add trait 重载 Point 实例的 + 运算符
add 方法将两个 Point 实例的 x 值和 y 值分别相加来创建一个新的 Point。Add trait 有一个叫做 Output
的关联类型,它用来决定 add 方法的返回值类型。
这里默认泛型类型位于 Add trait 中。这里是其定义:
trait Add<Rhs=Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
这些代码看来应该很熟悉,这是一个带有一个方法和一个关联类型的 trait。比较陌生的部分是尖括号中
的 Rhs=Self:这个语法叫做 默认类型参数(default type parameters)。Rhs 是一个泛型类型参数(”right
hand side” 的缩写),它用于定义 add 方法中的 rhs 参数。如果实现 Add trait 时不指定 Rhs 的具体类
型,Rhs 的类型将是默认的 Self 类型,也就是在其上实现 Add 的类型。
当为 Point 实现 Add 时,使用了默认的 Rhs,因为我们希望将两个 Point 实例相加。让我们看看一个实
现 Add trait 时希望自定义 Rhs 类型而不是使用默认类型的例子。
这里有两个存放不同单元值的结构体,Millimeters 和 Meters。(这种将现有类型简单封装进另一个结
构体的方式被称为 newtype 模式(newtype pattern,之后的 ” 为了类型安全和抽象而使用 newtype
模式” 部分会详细介绍。)我们希望能够将毫米值与米值相加,并让 Add 的实现正确处理转换。可以为
Millimeters 实现 Add 并以 Meters 作为 Rhs,如示例 19-15 所示。
文件名: src∕lib.rs
use std::ops::Add;
struct Millimeters(u32);
struct Meters(u32);
impl Add for Millimeters {
type Output = Millimeters;
fn add(self, other: Meters) -> Millimeters {
Millimeters(self.0 + (other.0 * 1000))
}
}
示例 19-15: 在 Millimeters 上实现 Add,以便能够将 Millimeters 与 Meters 相加
为了使 Millimeters 和 Meters 能够相加,我们指定 impl Add 来设定 Rhs 类型参数的值而不
是使用默认的 Self。
默认参数类型主要用于如下两个方面:
• 扩展类型而不破坏现有代码。
• 在大部分用户都不需要的特定情况进行自定义。
标准库的 Add trait 就是一个第二个目的例子:大部分时候你会将两个相似的类型相加,不过它提供了
自定义额外行为的能力。在 Add trait 定义中使用默认类型参数意味着大部分时候无需指定额外的参数。
换句话说,一小部分实现的样板代码是不必要的,这样使用 trait 就更容易了。
第一个目的是相似的,但过程是反过来的:如果需要为现有 trait 增加类型参数,为其提供一个默认类型
将允许我们在不破坏现有实现代码的基础上扩展 trait 的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值