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 中使用
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
特性: 创建一个命名的强类型。- 宏会自动实现常见的特性,如
Clone
、Debug
、Default
、PartialEq
、PartialOrd
、Send
和Sync
。它还默认实现Display
,除非被自定义_display 属性覆盖。 - 根据底层数据类型,条件性地实现
Copy
、Eq
、Ord
、Hash
等特性。对于如i32
或bool
这样的原始数据类型,这些附加的特性将被自动包含。 - 数值类型(整数和浮点数)也实现了常量
MIN
、MAX
、INFINITY
、NEG_INFINITY
和ZERO
。此外,对于浮点数类型,还实现了NAN
。
- 宏会自动实现常见的特性,如
-
属性
- 将以下属性添加到
#[strong_type(...)]
中,可以提供额外的功能auto_operators
:自动实现相关算术运算符(针对数值类型)或逻辑运算符(针对布尔类型)。addable
:自动实现Add
、Sub
和其他相关特质。该属性是auto_operators
的严格子集。scalable
:自动在强类型结构体及其原始类型之间实现Mul
、Div
、Rem
和其他相关特质。请注意,该属性不是auto_operators
的子集。custom_display
:允许用户手动实现Display
特质,提供默认显示格式的替代方案。conversion
:自动为底层类型实现From
和Into
特质。这是可选的,因为转换可能会使强类型不那么明显。underlying
:指定嵌套强类型的底层原始类型。
- 将以下属性添加到
安装
将strong-type
添加到您的Cargo.toml
文件中
[dependencies]
strong-type = "0.12"
支持的底层类型
- 整数类型:
i8
、i16
、i32
、i64
、i128
、isize
- 无符号整数类型:
u8
、u16
、u32
、u64
、u128
、usize
- 浮点类型:
f32
、f64
- 布尔类型:
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)]
时,特质Eq
和PartialEq
使用impl
实现。因此,StructuralEq
和StructuralPartialEq
尚未实现,阻止了与强类型原语的模式匹配。 #[strong_type(scalable)]
不适用于嵌套强类型。
依赖关系
~280–730KB
~18K SLoC