第6条:拥抱newtype模式第1条描述了元组结构体,它的字段没有名字,而是通过数字(self.0)来引用。本条着重介绍的是,只包含一个类型的元组结构体。它是一个新的类型,可以包含和内置类型一样的值。在Rust中,这个模式非常普遍,它叫做:newtype模式。newtype模
[第 1 条]描述了元组结构体,它的字段没有名字,而是通过数字(self.0
)来引用。本条着重介绍的是,只包含一个类型的元组结构体。它是一个新的类型,可以包含和内置类型一样的值。在 Rust 中,这个模式非常普遍,它叫做:newtype 模式。
newtype 模式的最简单用法,是在类型原有行为的基础上,提供[额外的语义]。想象有一个将卫星送往火星的项目。[^1]这是一个大项目,不同的团队已经构建了项目的不同部分。其中一个小组负责火箭引擎的代码:
/// 点燃推进器。返回产生的脉冲,单位为磅/秒。
pub fn thruster_impulse(direction: Direction) -> f64 {
// ...
return 42.0;
}
另一个团队负责惯性导航系统:
/// 根据提供的推力(单位:牛顿/秒)更新轨迹模型。
pub fn update_trajectory(force: f64) {
// ...
}
最终,结合这些不同部分:
let thruster_force: f64 = thruster_impulse(direction);
let new_direction = update_trajectory(thruster_force);
糟糕。[^2]
Rust 有类型别名的特性,让不同的团队能够更清楚地表达他们的意图:
/// 推力的单位。
pub type PoundForceSeconds = f64;
/// 点燃推进器。返回产生的脉冲。
pub fn thruster_impulse(direction: Direction) -> PoundForceSeconds {
// ...
return 42.0;
}
/// 推力的单位。
pub type NewtonSeconds = f64;
/// 更新冲力轨迹模型。
pub fn update_trajectory(force: NewtonSeconds) {
// ...
}
然而,实际上类型别名只是文档:它们比前面的文档注释有更强的提示,但不能阻止 PoundForceSeconds
值被使用在希望使用 NewtonSeconds
值的地方。
let thruster_force: PoundForceSeconds = thruster_impulse(direction);
let new_direction = update_trajectory(thruster_force);
再次出现问题了。
这就是 newtype 模式能带来帮助的地方
/// 推力的单位。
pub struct PoundForceSeconds(pub f64);
/// 点燃推进器。返回产生的脉冲。
pub fn thruster_impulse(direction: Direction) -> PoundForceSeconds {
// ...
return PoundForceSeconds(42.0);
}
/// 推力的单位。
pub struct NewtonSeconds(pub f64);
/// 更新冲力轨迹模型。
pub fn update_trajectory(force: NewtonSeconds) {
// ...
}
如名称所示,newtype 是一个新类型。因此,当型不匹配时,编译器会报错。在这里,我们尝试将 PoundForceSeconds
值传递给期望使用 NewtonSeconds
值的地方:
let thruster_force: PoundForceSeconds = thruster_impulse(direction);
let new_direction = update_trajectory(thruster_force);
let new_direction = update_trajectory(thruster_force);
error[E0308]: mismatched types
--> src/main.rs:76:43
|
76 | let new_direction = update_trajectory(thruster_force);
| ----------------- ^^^^^^^^^^^^^^ expected
| | `NewtonSeconds`, found `PoundForceSeconds`
| |
| arguments to this function are incorrect
|
note: function defined here
--> src/main.rs:66:8
|
66 | pub fn update_trajectory(force: NewtonSeconds) {
| ^^^^^^^^^^^^^^^^^ --------------------
help: call `Into::into` on this expression to convert `PoundForceSeconds` into
`NewtonSeconds`
|
76 | let new_direction = update_trajectory(thruster_...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!