在Rust中可以使用type构造来为现有类型创建一个别名。例如:
type Kilometers = i32; fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { x + y }
Kilometers只是i32的另一个名称;编译器不会区分这两种类型,它们是完全可以互换的。
新类型模式是为现有类型创建一个新的包装结构:
struct Kilometers(i32); // 一个独立的新类型 fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { Kilometers(x.0 + y.0) }
现在Kilometers和i32是不同的类型,不能混淆。
在这两种方法之间的选择取决于安全性和可读性的要求。对于开放API,特别是类型安全的测量单位,使用newtype。
在Rust中
type别名与新类型模式有什么区别?可以通过实现特性来限制类型别名的操作吗?
人们常常回答,别名可以用于控制访问和限制操作,但事实并非如此——别名不会产生新类型,因此无法为其实现独特的特性。只有新类型模式是一个独立的类型,可以为其实现独特的行为。
type UserId = u64; struct UserIdNew(u64); trait Foo { fn foo(&self); } // 无法为UserId实现Foo,因为它只是u64。 // 对于UserIdNew, 可以的。
历史
在项目中使用别名测量米和毫米的距离:
type Millimeters = u32; type Meters = u32;最终代码中不小心将毫米与米相加,导致计算错误。 类型检查没有发挥作用——编译器没有捕获到。转用新类型后问题解决。
历史
在公共API中使用别名用于不同实体的标识符(
type UserId = u64;,type OrderId = u64;)。出现了混淆:某人将参数搞错,导致错误进入生产环境,因为无法通过类型区分它们。
历史
开发人员试图为类型别名实现特性Display的独特行为:
type MyType = String; impl Display for MyType { ... }编译器报错:“无法为类型别名实现特性”。通过新类型模式解决了问题。