Rust类型包装库newtype-ops的使用:为NewType模式提供运算符重载和类型安全增强
Rust类型包装库newtype-ops的使用:为NewType模式提供运算符重载和类型安全增强
这是一个为NewType模式提供运算符重载和类型安全增强的Rust库,相比newtype_derive
提供了更灵活的操作。
示例代码
pub struct Foo(i32);
// 为Foo类型实现整数运算相关的所有运算符重载
newtype_ops! { [Foo] integer {:=} {^&}Self {^&}{Self i32} }
// 或者明确指定要实现哪些运算符
newtype_ops! { [Foo] {add sub mul div rem neg not bitand bitor bitxor} {:=} {^&}Self {^&}{Self i32} }
完整示例demo
// 添加依赖到Cargo.toml
// [dependencies]
// newtype-ops = "0.1"
use newtype_ops::newtype_ops;
// 定义NewType表示米和秒
pub struct Meters(f32);
pub struct Seconds(f32);
// 为Meters实现加法、减法、乘法和除法运算符
newtype_ops! { [Meters] {add sub mul div} {:=} {^&}Self {^&}{Self f32} }
// 为Seconds实现加法、减法、乘法和除法运算符
newtype_ops! { [Seconds] {add sub mul div} {:=} {^&}Self {^&}{Self f32} }
fn main() {
let m1 = Meters(5.0);
let m2 = Meters(3.0);
// 使用重载的运算符进行计算
let m3 = m1 + m2; // Meters(8.0)
let m4 = m1 - m2; // Meters(2.0)
let m5 = m1 * 2.0; // Meters(10.0)
println!("m3: {}, m4: {}, m5: {}", m3.0, m4.0, m5.0);
let s1 = Seconds(10.0);
let s2 = Seconds(4.0);
// 不同类型不能直接运算,保证了类型安全
// let error = m1 + s1; // 编译错误
// 需要相同类型才能运算
let s3 = s1 + s2; // Seconds(14.0)
println!("s3: {}", s3.0);
}
安装
在Cargo.toml中添加依赖:
[dependencies]
newtype-ops = "0.1"
许可证
WTFPL 2.0
1 回复
Rust类型包装库newtype-ops的使用:为NewType模式提供运算符重载和类型安全增强
介绍
newtype-ops
是一个Rust库,它为NewType模式提供了方便的运算符重载功能,同时保持类型安全性。NewType模式是Rust中通过包装现有类型来创建新类型的技术,常用于增加类型安全性和语义清晰度。
该库的主要特点:
- 为NewType自动派生常见运算符(+, -, *, /等)
- 保持编译时类型检查
- 减少NewType模式下的样板代码
- 支持自定义运算符实现
完整示例代码
下面是一个完整的示例,展示了如何使用newtype-ops
库来创建具有运算符重载功能的NewType:
// 引入newtype_ops宏和相关trait
use newtype_ops::{newtype_ops, Add, Sub, Mul, Div};
// 定义距离类型 - 自动派生所有支持的运算符
#[newtype_ops]
#[derive(Debug, Clone, Copy, PartialEq)]
struct Distance(f64);
// 定义时间类型 - 只选择性地派生Add和Sub运算符
#[newtype_ops(Add, Sub)]
#[derive(Debug, Clone, Copy, PartialEq)]
struct Time(f64);
// 定义速度类型 - 自定义运算符实现
#[newtype_ops(Add, Sub, Mul, Div)]
#[derive(Debug, Clone, Copy, PartialEq)]
struct Speed(f64);
// 自定义Speed的乘法实现
impl Mul<Time> for Speed {
type Output = Distance;
fn mul(self, rhs: Time) -> Self::Output {
Distance(self.0 * rhs.0)
}
}
// 自定义Distance的除法实现
impl Div<Time> for Distance {
type Output = Speed;
fn div(self, rhs: Time) -> Self::Output {
Speed(self.0 / rhs.0)
}
}
fn main() {
// 基本运算符使用
let d1 = Distance(10.0);
let d2 = Distance(5.0);
let sum_d = d1 + d2;
let diff_d = d1 - d2;
println!("距离相加: {:?}", sum_d); // Distance(15.0)
println!("距离相减: {:?}", diff_d); // Distance(5.0)
// 标量运算
let scaled_d = d1 * 2.0;
println!("距离缩放: {:?}", scaled_d); // Distance(20.0)
// 时间运算
let t1 = Time(2.0);
let t2 = Time(1.5);
let sum_t = t1 + t2;
println!("时间相加: {:?}", sum_t); // Time(3.5)
// 速度计算
let speed = Speed(50.0);
let distance = speed * t1;
println!("距离计算: {:?}", distance); // Distance(100.0)
// 速度计算反向
let new_speed = distance / t1;
println!("速度计算: {:?}", new_speed); // Speed(50.0)
// 类型安全示例 - 下面的代码会编译错误
// let invalid = d1 + t1; // 错误: 不能直接相加距离和时间
}
示例说明
-
基本NewType定义:
Distance
类型自动获得了所有基本运算符支持Time
类型只选择了加法和减法运算符
-
自定义运算符:
- 为
Speed
和Distance
实现了与Time
相乘和相除的特殊语义 - 乘法返回
Distance
,除法返回Speed
- 为
-
类型安全:
- 不同类型之间不能直接运算(如Distance + Time)
- 必须显式实现跨类型运算符
-
标量运算:
- 支持与基础类型(如f64)的运算
注意事项
- 使用
#[newtype_ops]
宏会自动派生所有支持的运算符,或者可以指定需要的运算符 - 默认支持的类型有:
Add
,Sub
,Mul
,Div
,Rem
,Neg
- 对于自定义类型,需要手动实现相应的trait
- 运算符重载不会自动支持不同类型的运算,这是为了保持类型安全
newtype-ops
库通过减少NewType模式下的样板代码,使得类型安全的编程更加方便,同时保持了Rust强大的类型系统优势。