5个版本
0.2.2 | 2024年5月26日 |
---|---|
0.2.1 | 2024年5月19日 |
0.1.3 | 2024年5月18日 |
#644 in Rust模式
48KB
713 行
枚举扩展库
此Rust包提供了procedural
和attribute
宏,用于增强Rust枚举类型的方法和转换。它通过自动生成常见任务的实用方法(如获取所有变体列表、计数变体以及在不同判别式和整型类型之间转换)来简化枚举的使用。
请参阅下面的enum_ext!
和#[enum_extend]
宏示例,获取更多信息。
这两个宏生成相同的实用方法,因此您可以选择最适合您编码风格的宏。
实用函数
list()
:返回包含枚举所有变体的数组。count()
:返回枚举中的变体数量。ordinal()
:返回变体的序号(索引)。from_ordinal(ordinal: usize)
:返回与给定序号对应的变体。ref_from_ordinal(ordinal: usize)
:返回指向与给定序号对应的变体的引用。valid_ordinal(ordinal: usize)
:检查给定的序号是否对枚举有效。iter()
:返回枚举所有变体的迭代器。from_<IntType>(value: <IntType>)
和as_<IntType>(&self)
:将指定整数类型进行转换,如果在该属性中定义了。- 例如,如果
IntType = "i32"
,则from_i32(10)
和as_i32()
,或者如果IntType = "u32"
,则from_u32(10)
和as_u32()
,等等。
- 例如,如果
pascal_spaced(&self)
:将变体名称转换为空格分隔的 PascalCase。例如,InQA
变为"In QA"
。from_pascal_spaced(name: &str)
:返回对应于空格分隔的 PascalCase 名称的变体。例如,"In QA"
变为InQA
。pretty_print()
:返回一个格式化的字符串,显示枚举及其所有变体,以漂亮的打印格式。- 更多内容即将到来...:请继续关注其他实用函数和特性。
请查看示例在存储库中获取更多信息属性.
属性是可选的,用于自定义生成的函数。
IntType
目前是唯一支持的属性,用于指定转换方法的判别类型。生成的函数允许将此类型转换为枚举变体,反之亦然。支持的类型包括标准 Rust 整数类型,如 i32
、u32
、i64
等。如果没有指定此属性,则使用 usize
作为默认值。
- 注意:如果枚举有判别值,则向枚举中添加
#[derive(Clone)]
(如果尚未存在)。- 属性分配略有不同,取决于使用的宏。
使用 enum_extend
时,属性直接应用于标签
使用 enum_ext!
时,属性应用于宏的 enum_def
参数
use enum_ext::enum_extend;
// example with no attribute
#[enum_extend]
#[derive(Debug, Clone, PartialEq)]
pub enum Discr1 {
A = 10,
B = 20,
C = 30,
}
// example with an attribute
#[enum_extend(IntType = "i32")] // <- `IntType` is the discriminant type for conversion methods
#[derive(Debug, Clone, PartialEq)]
pub enum Discr2 {
A = 10,
B = 20,
C = 30,
}
使用
use enum_ext::enum_ext;
enum_ext!(
#[enum_def(IntType = "i32")] // <- `IntType` is the discriminant type.
#[derive(Debug, Clone, PartialEq)]
pub enum AdvancedEnum {
A = 10,
B = 20,
C = 30,
}
);
用法
使用 #[enum_extend]
属性宏
要使用 enum_extend 属性宏,只需将其包含在你的 Rust 项目中,并将其应用于你的枚举定义。以下是一个示例:
fn main() {
use enum_ext::enum_extend;
#[enum_extend(IntType = "i32")]
#[derive(Debug, Default, Clone, PartialEq)]
pub enum AdvancedEnum {
#[default]
A = 10,
B = 20,
C = 30,
}
for x in AdvancedEnum::iter() {
let i = x.as_i32();
let v = AdvancedEnum::from_i32(i).unwrap();
assert_eq!(i, v.as_i32());
assert_eq!(*x, v); // This comparison requires that PartialEq be derived
}
let v = AdvancedEnum::from_i32(20).unwrap();
assert_eq!(v, AdvancedEnum::B);
}
使用 enum_ext!
过程宏
要使用 enum_ext!
宏,只需将其包含在你的 Rust 项目中,并将其应用于你的枚举定义。以下是一个示例:
fn main() {
use enum_ext::enum_ext;
enum_ext!(
#[derive(Debug, Clone, PartialEq)]
pub enum SimpleEnum {
A,
B,
C,
}
);
// With this, you can now use the generated methods on SimpleEnum:
let x = SimpleEnum::B;
assert_eq!(x.ordinal(), 1); // B is the second variant, so its ordinal is 1
let mut count = 0;
// enum_ext gives enums an iterator and variants can be iterated over
for x in SimpleEnum::iter() {
// The ordinal of the variant can be retrieved
let i = x.ordinal();
assert_eq!(i, count);
count += 1;
}
// enums also get a list method that returns an array of all variants
let list = SimpleEnum::list();
assert_eq!(list, [SimpleEnum::A, SimpleEnum::B, SimpleEnum::C]);
enum_ext!(
#[derive(Debug, Clone, Default, PartialEq)]
pub enum TicketStatus {
#[default]
Open,
InDev,
Completed,
InQA,
CodeReview,
FinalQA,
FinalCodeReview,
Accepted,
Closed,
}
);
// enums now have a pascal_spaced method that returns the variant name in spaced PascalCase.
// This is useful for displaying enum variants in a user-friendly format (e.g., in a UI).
// One example usage is converting InQA to "In QA" for display on a web page.
let status = TicketStatus::InQA;
assert_eq!(status.pascal_spaced(), "In QA");
// enums also get a from_pascal_spaced method that returns the variant from the spaced PascalCase name.
// This is useful for converting user-friendly format back to an enum variant.
// This is the reverse of the example above, converting "In QA" back to an enum.
let status2 = TicketStatus::from_pascal_spaced("In QA").unwrap();
assert_eq!(status2, TicketStatus::InQA);
}
为枚举变体生成了额外的实用方法
use enum_ext::enum_extend;
#[enum_extend(IntType = "i32")]
#[derive(Debug, PartialEq)]
pub enum DevelopmentStatus {
InDev = 10,
InQA = 20,
CodeReview = 30,
FinalQA = 40,
FinalCodeReview = 50,
Accepted = 60,
Closed = 70,
}
fn main() {
// Using list()
let variants = DevelopmentStatus::list();
assert_eq!(variants,
[DevelopmentStatus::InDev,
DevelopmentStatus::InQA,
DevelopmentStatus::CodeReview,
DevelopmentStatus::FinalQA,
DevelopmentStatus::FinalCodeReview,
DevelopmentStatus::Accepted,
DevelopmentStatus::Closed]);
// Using count()
let count = DevelopmentStatus::count();
assert_eq!(count, 7);
// Using ordinal()
let ordinal = DevelopmentStatus::CodeReview.ordinal();
assert_eq!(ordinal, 2); // CodeReview is the third variant, so its ordinal is 2
assert_eq!(DevelopmentStatus::from_ordinal(2), Some(DevelopmentStatus::CodeReview));
// Using iter()
for (i, variant) in DevelopmentStatus::iter().enumerate() {
assert_eq!(i, variant.ordinal());
}
// Using from_i32() and as_i32()
let variant = DevelopmentStatus::from_i32(20).unwrap();
assert_eq!(variant, DevelopmentStatus::InQA);
assert_eq!(variant.as_i32(), 20);
// Using pascal_spaced() method that returns the variant name in spaced PascalCase.
// This is useful for displaying enum variants in a user-friendly format (e.g., in a UI).
// One example usage is converting InQA to "In QA" for display on a web page.
let status = DevelopmentStatus::InQA;
assert_eq!(status.pascal_spaced(), "In QA");
// Using from_pascal_spaced() method that returns the variant from the spaced PascalCase name.
// This is useful for converting user-friendly format back to an enum variant.
// This is the reverse of the example above, converting "In QA" back to an enum.
let status2 = DevelopmentStatus::from_pascal_spaced("In QA").unwrap();
assert_eq!(status2, DevelopmentStatus::InQA);
}
入门指南
将以下内容添加到你的 Cargo.toml 文件中
[dependencies]
enum_ext = "0.2.2"
依赖项
~250–690KB
~17K SLoC