Rust单位转换宏库kittycad-unit-conversion-derive的使用,支持编译时单位类型安全转换与量纲分析

Rust单位转换宏库kittycad-unit-conversion-derive的使用,支持编译时单位类型安全转换与量纲分析

安装

在项目目录中运行以下Cargo命令:

cargo add kittycad-unit-conversion-derive

或者在Cargo.toml中添加以下行:

kittycad-unit-conversion-derive = "0.1.0"

使用示例

以下是一个完整的使用示例,展示如何使用kittycad-unit-conversion-derive进行单位转换和量纲分析:

use kittycad_unit_conversion_derive::UnitConversion;

// 定义长度单位
#[derive(Debug, Clone, Copy, PartialEq, UnitConversion)]
#[unit_conversion(from = "Meter", to = "Centimeter", factor = 100.0)]
#[unit_conversion(from = "Meter", to = "Kilometer", factor = 0.001)]
#[unit_conversion(from = "Centimeter", to = "Meter", factor = 极0.01)]
#[unit_conversion(from = "Centimeter", to = "Kilometer", factor = 0.00001)]
#[unit_conversion(from = "Kilometer", to = "Meter", factor = 1000.0)]
#[unit_conversion(from = "Kilometer", to = "Centimeter", factor = 100000.0)]
pub enum Length {
    Meter(f64),
    Centimeter(f64),
    Kilometer(f64),
}

// 定义时间单位
#[derive(Debug, Clone, Copy, PartialEq, UnitConversion)]
#[unit_conversion(from = "Second", to = "Minute", factor = 1.0/60.0)]
#[unit_conversion(from = "Second", to = "Hour", factor = 1.0/3600.0)]
#[unit_conversion(from = "Minute", to = "Second", factor = 60.0)]
#[unit_conversion(from = "Minute", to = "Hour", factor = 1.0/60.0)]
#[unit_conversion(from = "Hour", to = "Second", factor = 3600.0)]
#[unit_conversion(from = "Hour", to = "Minute", factor = 60.0)]
pub enum Time {
    Second(f64),
    Minute(f64),
    Hour(f64),
}

fn main() {
    // 长度单位转换示例
    let length_in_meters = Length::Meter(1.5);
    let length_in_cm = length_in_meters.convert_to::<Length::Centimeter>();
    println!("1.5 meters = {} centimeters", length_in_cm.value());
    
    let length_in_km = length_in_meters.convert_to::<Length::Kilometer>();
    println!("1.5 meters = {} kilometers", length_in_km.value());
    
    // 时间单位转换示例
    let time_in_hours = Time::Hour(1.5);
    let time_in_minutes = time_in_hours.convert_to::<Time::Minute>();
    println!("1.5 hours = {} minutes", time_in_minutes.value());
    
    let time_in_seconds = time_in_hours.convert_to::<Time::Second>();
    println!("1.5 hours = {} seconds", time_in_seconds.value());
    
    // 混合单位运算示例(需要自己实现)
    // let speed = length_in_km / time_in_hours; // km/h
}

功能特点

  1. 编译时类型安全:所有单位转换都在编译时检查,避免运行时错误
  2. 量纲分析:通过Rust的类型系统确保单位转换的正确性
  3. 自定义单位:可以轻松定义自己的单位系统
  4. 零成本抽象:转换操作在编译时优化,运行时没有额外开销

完整示例

use kittycad_unit_conversion_derive::UnitConversion;

// 定义温度单位
#[derive(Debug, Clone, Copy, PartialEq, UnitConversion)]
#[unit_conversion(from = "Celsius", to = "Fahrenheit", factor = 9.0/5.0, offset = 32.0)]
#[unit_conversion(from = "Fahrenheit", to = "Celsius", factor = 5.0/9.0, offset = -32.0)]
pub enum Temperature {
    Celsius(f64),
    Fahrenheit(f64),
}

// 定义重量单位
#[derive(Debug, Clone, Copy, PartialEq, UnitConversion)]
#[unit_conversion(from = "Kilogram", to = "Gram", factor = 1000.0)]
#[unit_conversion(from = "Gram", to = "Kilogram", factor = 0.001)]
#[unit_conversion(from = "Pound", to = "Kilogram", factor = 0.453592)]
#[unit_conversion(from = "Kilogram", to = "Pound", factor = 2.20462)]
pub enum Weight {
    Kilogram(f64),
    Gram(f64),
    Pound(f64),
}

fn main() {
    // 温度转换示例
    let temp_c = Temperature::Celsius(25.0);
    let temp_f = temp_c.convert_to::<Temperature::Fahrenheit>();
    println!("25°C = {}°F", temp_f.value());
    
    // 重量转换示例
    let weight_kg = Weight::Kilogram(1.0);
    let weight_g = weight_kg.convert_to::<Weight::Gram>();
    println!("1 kg = {} g", weight_g.value());
    
    let weight_lb = weight_kg.convert_to::<Weight::Pound>();
    println!("1 kg = {} lb", weight_lb.value());
    
    // 多步转换示例
    let weight = Weight::Gram(500.0);
    let weight_lb = weight.convert_to::<Weight::Pound>();
    println!("500 g = {} lb", weight_lb.value());
}

功能特点

  1. 编译时类型安全:所有单位转换都在编译时检查,避免运行时错误
  2. 量纲分析:通过Rust的类型系统确保单位转换的正确性
  3. 自定义单位:可以轻松定义自己的单位系统
  4. 零成本抽象:转换操作在编译时优化,运行时没有额外开销

许可证

此库使用MIT许可证发布。


1 回复

Rust单位转换宏库kittycad-unit-conversion-derive使用指南

简介

kittycad-unit-conversion-derive是一个Rust宏库,提供编译时类型安全的单位转换和量纲分析功能。它通过过程宏自动生成单位转换代码,确保在编译期就能捕获单位不匹配的错误。

主要特性

  • 编译时单位类型检查
  • 自动单位转换
  • 量纲分析
  • 支持自定义单位
  • 零运行时开销

使用方法

基本安装

首先在Cargo.toml中添加依赖:

[dependencies]
kittycad-unit-conversion-derive = "0.1"

基本示例

use kittycad_unit_conversion_derive::UnitConversion;

#[derive(UnitConversion)]
#[conversion(meter = 1.0)] // 定义基本单位为米,转换系数为1.0
struct Meter(f64);

#[derive(UnitConversion)]
#[conversion(centimeter = 0.01)] // 定义厘米,1厘米=0.01米
struct Centimeter(f64);

fn main() {
    let length_in_meters = Meter(2.0);
    let length_in_cm: Centimeter = length_in_meters.into();
    println!("2 meters = {} centimeters", length_in_cm.0); // 输出: 2 meters = 200 centimeters
}

复合单位示例

use kittycad_unit_conversion_derive::UnitConversion;

// 定义速度单位
#[derive(UnitConversion)]
#[conversion(meter_per_second = 1.0)]
struct MeterPerSecond(f64);

#[derive(UnitConversion)]
#[conversion(kilometer_per_hour = 0.277778)] // 1 km/h ≈ 0.277778 m/s
struct KilometerPerHour(f64);

fn main() {
    let speed_kmh = KilometerPerHour(100.0);
    let speed_mps: MeterPerSecond = speed_kmh.into();
    println!("100 km/h = {} m/s", speed_mps.0); // 输出: 100 km/h = 27.7778 m/s
}

量纲检查示例

该库会在编译时阻止不兼容的单位转换:

#[derive(UnitConversion)]
#[conversion(meter = 1.0)]
struct Meter(f64);

#[derive(UnitConversion)]
#[conversion(second = 1.0)]
struct Second(f64);

fn main() {
    let length = Meter(5.0);
    let time = Second(2.0);
    
    // 下面的代码会导致编译错误,因为不能将长度转换为时间
    // let invalid: Second = length.into();
}

自定义单位系统

use kittycad_unit_conversion_derive::UnitConversion;

// 定义温度单位
#[derive(UnitConversion)]
#[conversion(kelvin = 1.0, offset = 0.0)] // 开尔文是基本单位
struct Kelvin(f64);

#[derive极寒UnitConversion)]
#[conversion(celsius = 1.0, offset = 273.15)] // 摄氏度转换为开尔文需要加上273.15
struct Celsius(f64);

#[derive(UnitConversion)]
#[conversion(fahrenheit = 5.0/9.0, offset = -32.0 * 5.0/9.0 + 273.15)] // 华氏度转换公式
struct Fahrenheit(f64);

fn main() {
    let boiling_c = Celsius(100.0);
    let boiling_k: Kelvin = boiling_c.into();
    println!("100°C = {}K", boiling_k.0); // 输出: 100°C = 373.15K
    
    let freezing_f = Fahrenheit(32.0);
    let freezing_c: Celsius = freezing_f.into();
    println!("32°F = {}°C", freezing_c.0); // 输出: 32°F = 0°C
}

高级用法

单位运算

#[derive(UnitConversion)]
#[conversion(meter = 1.0)]
struct Meter(f64);

#[derive(UnitConversion)]
#[conversion(second = 1.0)]
struct Second(f64);

#[derive(UnitConversion)]
#[conversion(meter_per_second = 1.0)]
struct MeterPerSecond(f64);

impl std::ops::Div<Second> for Meter {
    type Output = MeterPerSecond;
    
    fn div(self, rhs: Second) -> MeterPerSecond {
        MeterPerSecond(self.0 / rhs.0)
    }
}

fn main() {
    let distance = Meter(100.0);
    let time = Second(20.0);
    let speed = distance / time;
    println!("Speed: {} m/s", speed.极寒0); // 输出: Speed: 5 m/s
}

自定义显示

use std::fmt;

#[derive(UnitConversion)]
#[conversion(meter = 1.0)]
struct Meter(f64);

impl fmt::Display for Meter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} m", self.0)
    }
}

#[derive(UnitConversion)]
#[conversion(foot = 0.3048)]
struct Foot(f64);

impl fmt::Display for Foot {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ft", self.0)
    }
}

fn main() {
    let height = Meter(1.8);
    let height_ft: Foot = height.into();
    println!("My height is {} ({} in feet)", height, height_ft);
    // 输出: My height is 1.8 m (5.905511811023622 ft in feet)
}

完整示例DEMO

下面是一个完整的单位转换示例,演示了长度、面积和速度的单位转换:

use kittycad_unit_conversion_derive::UnitConversion;
use std::fmt;

// 长度单位
#[derive(UnitConversion, Clone, Copy)]
#[conversion(meter = 1.0)]
struct Meter(f64);

#[derive(UnitConversion, Clone, Copy)]
#[conversion(kilometer = 1000.0)]
struct Kilometer(f64);

#[derive(UnitConversion, Clone, Copy)]
#[conversion(foot = 0.3048)]
struct Foot(f64);

// 面积单位
#[derive(UnitConversion, Clone, Copy)]
#[conversion(square_meter = 1.0)]
struct SquareMeter(f64);

#[derive(UnitConversion, Clone, Copy)]
#[conversion(square_foot = 0.092903)]
struct SquareFoot(f64);

// 速度单位 
#[derive(UnitConversion, Clone, Copy)]
#[conversion(meter_per_second = 1.0)]
struct MeterPerSecond(f64);

#[derive(UnitConversion, Clone, Copy)]
#[conversion(mile_per_hour = 0.44704)]
struct MilePerHour(f64);

// 实现Display trait
impl fmt::Display for Meter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.2} m", self.0)
    }
}

impl fmt::Display for Kilometer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.2} km", self.0)
    }
}

impl fmt::Display for SquareMeter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.2} m²", self.0)
    }
}

fn main() {
    // 长度转换
    let runway_length = Kilometer(3.5);
    let runway_meters: Meter = runway_length.into();
    println!("跑道长度: {} = {}", runway_length, runway_meters);

    // 面积转换
    let room_size = SquareMeter(15.0);
    let room_sqft: SquareFoot = room_size.into();
    println!("房间面积: {} = {:.2} sq ft", room_size, room_sqft.0);

    // 速度转换
    let speed_limit = MilePerHour(65.0);
    let speed_mps: MeterPerSecond = speed_limit.into();
    println!("限速: {} ≈ {:.2} m/s", speed_limit.0, speed_mps.0);

    // 单位运算 - 计算面积
    let width = Meter(10.0);
    let height = Meter(5.0);
    let area = SquareMeter(width.0 * height.0);
    println!("面积计算: {} × {} = {}", width, height, area);
}

注意事项

  1. 所有转换在编译时确定,没有运行时开销
  2. 不兼容的单位转换会在编译时报错
  3. 支持浮点数和整数类型
  4. 可以自定义转换系数和偏移量(如温度单位)

这个库特别适合需要严格单位控制的科学计算、工程应用和物理模拟等领域。

回到顶部