18 个版本 (11 个重大更新)

0.13.2 2024年7月27日
0.12.1 2024年4月5日
0.12.0 2023年5月15日
0.11.0 2022年8月19日
0.1.1 2021年12月19日

#49数学

Download history 13/week @ 2024-04-27 9/week @ 2024-05-04 10/week @ 2024-05-11 20/week @ 2024-05-18 10/week @ 2024-05-25 14/week @ 2024-06-01 8/week @ 2024-06-08 3/week @ 2024-06-15 3/week @ 2024-06-22 1/week @ 2024-06-29 3/week @ 2024-07-06 22/week @ 2024-07-13 136/week @ 2024-07-20 358/week @ 2024-07-27 4/week @ 2024-08-03 3/week @ 2024-08-10

502 每月下载
用于 2 crates

自定义许可证

95KB
1.5K SLoC

使用数量进行单元安全计算。

什么是数量?

"数量的值通常表示为数字和单位的乘积。单位是数量相关的一个特定示例,用作参考,而数字是数量值与单位的比值。"(国际度量衡局:国际单位制,第8版,2006年)

基本类型的数量是通过“惯例”定义的,它们不依赖于其他类型的数量,例如长度、质量或持续时间。

导出类型的数量,相反,被定义为其他类型数量乘以某些指数的乘积。

示例

  • 体积 = 长度³

  • 速度 = 长度¹ · 持续时间⁻¹

  • 加速度 = 长度¹ · 持续时间⁻²

  • 力 = 质量¹ · 加速度¹

每种类型的数量可能有一个特殊单位,用作所有其他单位的参考,例如米、千克和秒。其他单位然后根据它们与参考单位的关系定义。

如果一个类型的数量是从所有都具有参考单位的类型派生出来的,那么该类型的参考单位由一个公式定义,该公式遵循定义数量类型的公式。

示例

  • 速度 -> 每秒米 = 米¹ · 秒⁻¹

  • 加速度 -> 每秒平方米 = 米¹ · 秒⁻²

  • 力 -> 牛顿 = 千克¹ · 米¹ · 秒⁻²

"度量系统"

可能有不同的系统定义数量、它们的单位和这些单位之间的关系,方式不同。

此包不直接支持此功能。对于每种类型的数量,可以有零个或恰好一个参考单位。但是,如果您有同一类型数量的不同系统的单位,您可以定义这些单位并提供在这些单位之间进行转换的机制。

基础知识:数量和单位

该包的基本功能由特性 QuantityHasRefUnitUnitLinearScaledUnit 以及用于生成具体数量类型的代码的宏提供。

可以使用 proc-macro 属性 quantity 轻易地定义一种 基本 类型的数量,可选地跟随一个属性 refunit,然后至少跟随一个属性 unit

该宏生成一个枚举,具有给定的单位(包括如果提供则 refunit)作为变体(同时实现特性 Unit 以及如果有参考单位则特性 LinearScaledUnit),一个以给定结构体命名的类型,为此类型实现特性 Quantity,如果有参考单位则实现特性 HasRefUnit,以及一些 std 特性的实现。

此外,它为每个枚举变体创建一个常量,因此为每个单位提供一个常量。这意味着所有定义的数量中所有单位的标识符都必须是唯一的!

示例

# use quantities::prelude::*;
#[quantity]
#[ref_unit(Kilogram, "kg", KILO)]
#[unit(Milligram, "mg", MILLI, 0.000001)]
#[unit(Carat, "ct", 0.0002)]
#[unit(Gram, "g", NONE, 0.001)]
#[unit(Ounce, "oz", 0.028349523125)]
#[unit(Pound, "lb", 0.45359237)]
#[unit(Stone, "st", 6.35029318)]
#[unit(Tonne, "t", MEGA, 1000.)]
/// The quantity of matter in a physical body.
struct Mass {}

assert_eq!(MILLIGRAM.name(), "Milligram");
assert_eq!(POUND.symbol(), "lb");
assert_eq!(TONNE.si_prefix(), Some(SIPrefix::MEGA));
assert_eq!(CARAT.scale(), Amnt!(0.0002));

为了创建基于更基本数量类型的 派生 类型的数量,可以将表达式作为 proc-macro 属性 quantity 的参数,指定数量作为两个基本数量的乘积或商。

然后可以通过乘以或除以基本数量的实例来构建派生数量的实例。将定义为乘积的数量除以基本数量之一的实例,得到另一个基本数量的实例。将定义为商的数量乘以除数数量的实例,得到被除数数量的实例。

示例

# use quantities::prelude::*;
#[quantity]
#[ref_unit(Meter, "m", NONE, "Reference unit of quantity `Length`")]
#[unit(Centimeter, "cm", CENTI, 0.01, "0.01·m")]
#[unit(Kilometer, "km", KILO, 1000, "1000·m")]
#[unit(Mile, "mi", 1609.344, "8·fur")]
pub struct Length {}

#[quantity]
#[ref_unit(Second, "s", NONE, "Reference unit of quantity `Duration`")]
#[unit(Minute, "min", 60, "60·s")]
#[unit(Hour, "h", 3600, "60·min")]
pub struct Duration {}

#[quantity(Length * Length)]
#[ref_unit(Square_Meter, "", NONE, "Reference unit of quantity `Area`")]
#[unit(Square_Centimeter, "cm²", 0.00001, "cm²")]
#[unit(Square_Kilometer, "km²", MEGA, 1000000., "km²")]
pub struct Area {}

let a = Amnt!(3.) * METER;
let b = Amnt!(0.5) * KILOMETER;
let ab = a * b;
assert_eq!(ab, Amnt!(1500.) * SQUARE_METER);
let c = ab / (Amnt!(2.) * KILOMETER);
assert_eq!(c, Amnt!(0.75) * METER);

#[quantity(Length / Duration)]
#[ref_unit(Meter_per_Second, "m/s", NONE, "Reference unit of quantity `Speed`")]
#[unit(Miles_per_Hour, "mph", 0.44704, "mi/h")]
pub struct Speed {}

let l = Amnt!(150.) * MILE;
let t = Amnt!(1.2) * HOUR;
let v = l / t;
assert_eq!(v, Amnt!(125.) * MILES_PER_HOUR);
let d = v * Duration::new(Amnt!(3.), HOUR);
assert_eq!(d, Amnt!(375.) * MILE);

数值部分类型

该包允许为 Quantity 值的数值部分使用 floatfixed-point decimal 值。

内部使用类型别名 AmountT。此别名可以通过可选功能 fpdec(参见 功能)进行控制。

当功能 fpdec 关闭(=默认)时,AmountT 在 64 位系统上定义为 f64 或者在 32 位系统上定义为 f32

当功能 fpdec 激活时,AmountT 定义为 Decimal(从 crate fpdec 导入)。

可以使用宏 Amnt! 将浮点字面值正确地转换为 AmountT,具体取决于配置。这是通过上述描述的 proc-macro quantity 自动为单位的刻度值完成的。

实例化数量

可以通过调用函数 new 创建数量类型的实例,提供一个数量和一个单位。或者,可以乘以一个数量和一个单位。

示例

# use quantities::prelude::*;
# #[quantity]
# #[ref_unit(Kilogram, "kg", KILO)]
# #[unit(Gram, "g", NONE, 0.001)]
# struct Mass {}
let m = Mass::new(Amnt!(17.4), GRAM);
assert_eq!(m.to_string(), "17.4 g");
let m = Amnt!(17.4) * GRAM;
assert_eq!(m.to_string(), "17.4 g");

单位安全计算

如果数量类型有一个参考单位,可以通过调用方法 convert 将数量实例转换为同一类型的具有不同单位的数量实例。

示例

# use quantities::prelude::*;
# #[quantity]
# #[ref_unit(Kilogram, "kg", KILO)]
# #[unit(Carat, "ct", 0.0002)]
# #[unit(Gram, "g", NONE, 0.001)]
# struct Mass {}
let x = Mass::new(Amnt!(13.5), GRAM);
let y = x.convert(CARAT);
assert_eq!(y.to_string(), "67.5 ct");

具有相同单位的数量值始终可以相加或相减。具有不同单位的值相加或相减需要值可转换。

示例

# use quantities::prelude::*;
# #[quantity]
# #[ref_unit(Kilogram, "kg", KILO)]
# #[unit(Gram, "g", NONE, 0.001)]
# struct Mass {}
let x = Amnt!(17.4) * GRAM;
let y = Amnt!(1.407) * KILOGRAM;
let z = x + y;
assert_eq!(z.amount(), Amnt!(1424.4));
assert_eq!(z.unit(), GRAM);
let z = y + x;
assert_eq!(z.to_string(), "1.4244 kg");

数量值始终可以乘以或除以数值,保留单位。

示例

# use quantities::prelude::*;
# #[quantity]
# #[ref_unit(Kilogram, "kg", KILO)]
# #[unit(Gram, "g", NONE, 0.001)]
# struct Mass {}
let x = Amnt!(7.4);
let y = Amnt!(1.7) * KILOGRAM;
let z = x * y;
assert_eq!(z.to_string(), "12.58 kg");

常用量

该软件包提供可选模块,其中包含常用量的定义;每个都可以通过具有相应名称的功能来激活(见下文)。

箱特征

默认情况下,只有功能 std 被启用。

生态系统

  • std - 当启用时,这将导致 quantities 使用标准库,以便可以使用字符串转换、格式化和打印。当禁用时,需要使用 alloc 箱以及特定于系统的分配器来使用该功能。

可选依赖

  • fpdec - 当启用时,将使用 f64f32 代替 fpdec::Decimal 作为 AmountT(见上文)。

  • serde - 当启用时,启用对 serde 的支持。

预定义量

以下功能可以启用附加模块,每个都提供预定义量。

  • mass - 模块 [mass] - 量 质量
  • length - 模块 [length] - 量 长度
  • duration - 模块 [duration] - 量 持续时间
  • area - 模块 [area] - 量 面积
  • volume - 模块 [volume] - 量 体积
  • speed - 模块 [speed] - 量 速度
  • acceleration - 模块 [acceleration] - 量 加速度
  • force - 模块 [force] - 量
  • energy - 模块 [energy] - 量 能量
  • power - 模块 [power] - 量 功率
  • frequency - 模块 [frequency] - 量 频率
  • datavolume - 模块 [datavolume] - 量 数据量
  • datathroughput - 模块 [datathroughput] - 量 数据吞吐量
  • temperature - 模块 [temperature] - 量 温度

依赖关系

~0.9–1.5MB
~29K SLoC