bitflags 在宏三大法器中抢夺出了前四名中的一席之地。它本身的功能相当简单。直接看代码:
bitflags::bitflags! {
pub struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
}
}
或是
pub struct Flags(u32);
bitflags! {
impl Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
}
}
然后就可以把 Flags
类似 u128
一样计算使用,不同的是它基于 Flags
trait 实现了一些好方法,如同官方 slice
一样,让我们能够轻松使用。
这是一种值得学习的范式:用 declarative macro 实现最小化扩展,然后用一个 trait 实现更多方法。
宏
让我们深入看看 bitflags 的实际实现:教科书式的 declarative macro。
$(#[$outer:meta])*
$vis:vis struct $BitFlags:ident: $T:ty {
$(
$(#[$inner:ident $($args:tt)*])*
const $Flag:tt = $value:expr;
)*
}
$($t:tt)*
首先它处理了内外的 metadata;以支持诸如嵌套 macro、文档注释、编译标记等额外信息。
然后是逐步的函数式 declarative macro 实现。
它在最后处理了额外的 Token Tree,以支持多类型定义。
总之简单好用就完了。