#strongly-typed #primitive #string

strong-type-derive

为 #[derive(StrongType)] 实现宏

11个版本 (重大更改)

0.12.0 2024年6月17日
0.11.0 2024年4月14日
0.10.0 2024年3月6日
0.5.0 2023年12月27日

#11 in #strong-typing

每月46次下载
strong-type 中使用

MIT/Apache

49KB
1K SLoC

strong-type

strong-type 是一个Rust库,提供宏以轻松创建强类型和命名的原始和字符串类型。强类型有助于使代码更具表达性和更不容易出错,确保每个类型都按照其预期的方式使用。

use strong_type::StrongType;

#[derive(StrongType)]
struct Timestamp(i64);

let timestamp = Timestamp::new(1701620628123456789);
println!("{}", timestamp); // Timestamp(1701620628123456789)

功能

  • 实现 StrongType 特性: 创建一个命名的强类型。

    • 宏会自动实现常见的特性,如 CloneDebugDefaultPartialEqPartialOrdSendSync。它还默认实现 Display,除非被自定义_display 属性覆盖。
    • 根据底层数据类型,条件性地实现 CopyEqOrdHash 等特性。对于如 i32bool 这样的原始数据类型,这些附加的特性将被自动包含。
    • 数值类型(整数和浮点数)也实现了常量 MINMAXINFINITYNEG_INFINITYZERO。此外,对于浮点数类型,还实现了 NAN
  • 属性

    • 将以下属性添加到 #[strong_type(...)] 中,可以提供额外的功能
      • auto_operators:自动实现相关算术运算符(针对数值类型)或逻辑运算符(针对布尔类型)。
      • addable:自动实现AddSub和其他相关特质。该属性是auto_operators的严格子集。
      • scalable:自动在强类型结构体及其原始类型之间实现MulDivRem和其他相关特质。请注意,该属性不是auto_operators的子集。
      • custom_display:允许用户手动实现Display特质,提供默认显示格式的替代方案。
      • conversion:自动为底层类型实现FromInto特质。这是可选的,因为转换可能会使强类型不那么明显。
      • underlying:指定嵌套强类型的底层原始类型。

安装

strong-type添加到您的Cargo.toml文件中

[dependencies]
strong-type = "0.12"

支持的底层类型

  • 整数类型:i8i16i32i64i128isize
  • 无符号整数类型:u8u16u32u64u128usize
  • 浮点类型:f32f64
  • 布尔类型:bool
  • 字符
  • 字符串
  • 上述类型的强类型

示例

创建命名强类型

具有私有字段

use strong_type::StrongType;

#[derive(StrongType)]
struct Tag(String);

let tag = Tag::new("dev");
const TAG: Tag = Tag::const_new("prod");

具有公共字段

use strong_type::StrongType;

#[derive(StrongType)]
struct Timestamp(pub i64);

let timestamp = Timestamp(1701620628123456789);
println!("{}", timestamp); // Timestamp(1701620628123456789)

展示类型独特性

use strong_type::StrongType;
use std::any::Any;

#[derive(StrongType)]
struct Second(i32);

#[derive(StrongType)]
struct Minute(i32);

let x = Second::new(2);
let y = Second::new(3);
let z = Minute::new(3);

assert_eq!(x.type_id(), y.type_id()); // Same type: Second
assert_ne!(y.type_id(), z.type_id()); // Different types: Second versus Minute

利用可哈希性

use std::collections::HashSet;

#[derive(StrongType)]
struct Tag(String);

let mut map = HashSet::<Tag>::new();
map.insert(Tag::new("dev"));
map.insert(Tag::new("prod"));
assert_eq!(map.len(), 2);

具有算术运算的命名整数类型

use strong_type::StrongType;

#[derive(StrongType)]
#[strong_type(auto_operators)]
struct Nanosecond(u32);

let x = Nanosecond::new(2);
let y = Nanosecond::new(3);
let z = Nanosecond::default();

assert_eq!(x.value(), 2);
assert_eq!(y.value(), 3);
assert_eq!(z.value(), 0);
assert!(x < y);
assert!(y >= x);
assert_eq!(x + y, Nanosecond(5));

#[derive(StrongType)]
#[strong_type(scalable)]
struct Millisecond(u32);

let x = Millisecond::new(2);

assert_eq!(x * 3, Millisecond(6));

具有逻辑运算的命名布尔类型

use strong_type::StrongType;

#[derive(StrongType)]
#[strong_type(auto_operators)]

struct IsTrue(bool);

let x = IsTrue::new(true);
let y = IsTrue::new(false);

assert_eq!(x & y, IsTrue::new(false));
assert_eq!(x | y, IsTrue::new(true));
assert_eq!(x ^ y, IsTrue::new(true));
assert_eq!(!x, IsTrue::new(false));

使用custom_display自定义显示实现

use std::fmt::{Display, Formatter, Result};
use strong_type::StrongType;

#[derive(StrongType)]
#[strong_type(custom_display)]

struct Second(f64);

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

println!("{}", Second::new(std::f64::consts::E)); // "Second(2.72)"
println!("{:?}", Second::new(std::f64::consts::E)); // "Second { value: 2.718281828459045 }"

嵌套强类型

#[derive(StrongType)]
#[strong_type(auto_operators)]
struct Dollar(i32);

#[derive(StrongType)]
#[strong_type(auto_operators, underlying = i32)]
struct Cash(Dollar);

#[derive(StrongType)]
#[strong_type(underlying = i32)]
struct Coin(Cash);

注意事项

  • 当使用#[derive(StrongType)]时,特质EqPartialEq使用impl实现。因此,StructuralEqStructuralPartialEq尚未实现,阻止了与强类型原语的模式匹配。
  • #[strong_type(scalable)]不适用于嵌套强类型。

依赖关系

~280–730KB
~18K SLoC