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; // 错误: 不能直接相加距离和时间
}

示例说明

  1. 基本NewType定义

    • Distance类型自动获得了所有基本运算符支持
    • Time类型只选择了加法和减法运算符
  2. 自定义运算符

    • SpeedDistance实现了与Time相乘和相除的特殊语义
    • 乘法返回Distance,除法返回Speed
  3. 类型安全

    • 不同类型之间不能直接运算(如Distance + Time)
    • 必须显式实现跨类型运算符
  4. 标量运算

    • 支持与基础类型(如f64)的运算

注意事项

  1. 使用#[newtype_ops]宏会自动派生所有支持的运算符,或者可以指定需要的运算符
  2. 默认支持的类型有:Add, Sub, Mul, Div, Rem, Neg
  3. 对于自定义类型,需要手动实现相应的trait
  4. 运算符重载不会自动支持不同类型的运算,这是为了保持类型安全

newtype-ops库通过减少NewType模式下的样板代码,使得类型安全的编程更加方便,同时保持了Rust强大的类型系统优势。

回到顶部