2 个版本
0.1.1 | 2022年5月21日 |
---|---|
0.1.0 | 2022年5月21日 |
2355 在 开发工具
94 每月下载次数
在 5 crate 中使用
18KB
227 行
dry
— 别重复自己
Rust 宏,用于代码的惯用去重。当 macro_rules!
过于强大且笨拙时使用。
[dependencies]
dry = "0.1.1"
用法
macro_for!
您熟悉可靠的 for
循环
for number in [1, 2, 3, 4, 5] {
println!("{}", number);
}
使用 macro_for!
在编译时迭代标记
macro_for!($Struct in [A, B, C, D, E] {
struct $Struct {
many_fields: bool,
so_many_fields: bool,
impossibly_many_fields: bool,
}
});
与使用 macro_rules!
相比
macro_rules! my_struct {
($Struct:ident) => {
struct $Struct {
many_fields: bool,
so_many_fields: bool,
impossibly_many_fields: bool,
}
};
}
my_struct!(A);
my_struct!(B);
my_struct!(C);
my_struct!(D);
my_struct!(E);
请参阅 示例 以获取更多详细信息。
macro_wrap!
允许您在宏调用非法的位置(例如结构体字段、枚举情况、match 分支)中使用此 crate 中的其他宏。
包装最接近的宏调用位置的上层语法树祖先,然后就可以使用了
macro_wrap!(match x {
// ↓ can't usually call macros here, but `macro_wrap!` makes it work
macro_for!($Variant in [A, B, C, D, E] {
Enum::$Variant => 1,
})
})
特性
nightly
特性(默认禁用)启用使用不稳定的 proc_macro_span
rustc 功能。它启用更好的语法检查(禁止 "$" 和替换变量名之间的空格)并在错误时发出更多的源代码提示(尽管宏的快速修复功能即使在 nightly 版本中也不可用)。
如果您正在运行 Rust nightly,您可以启用它
[dependencies]
dry = { version = "0.1.1", features = ["nightly"] }
关于此 crate
依赖关系
唯一的依赖是 proc-macro-error
,用于在不同 Rust 版本之间提供甜美的、友好的错误消息。反过来,它依赖于 quote
和 proc-macro2
。然而,我们完全不依赖 syn
,因此 dry
应该在编译时间上非常轻量。
注意
如果可能,您应该尝试使用循环、特性和泛型等抽象。但是当无法这样做时,dry
会尽可能使避免重复变得不那么痛苦和愉快。
先前的艺术
For Each 循环
duplicate
:目前最受欢迎的,其工作方式与普通的for
循环类似,具有元组解构,但语法非常陌生。它提供了一种属性语法,可以避免一些嵌套,但在我看来,这牺牲了清晰度。函数式语法可以在属性语法有效的地方使用,另外,“$”前缀的标识符在Rust中是无效的,因此不可能在属性语法中实现。akin
:通过隐式for comprehension扩展了let
语法。它避免了大量替换变量的嵌套,但在我看来,它感觉过于神奇,不太适合大多数Rust代码库。ct-for
:几乎达到了目的!然而,它使用了in ... do
语法,而不是Rust程序员更熟悉的in ... {}
语法。这也使得编辑器更难正确缩进循环体。最后,ct
在ct_for
中的描述性不是很强。
所有这些都在循环体内部使用裸标识符而不是“$”前缀标识符(如dry
和macro_rules!
),这使得在循环体内部使用宏与标准语言特性之间的区别变得清晰。据我所知,它们都不支持复制结构体字段、枚举案例或匹配分支。
重复N次
repeated
:虽然不是同一件事,但它提醒作者注意宏调用位置(例如,匹配分支等)问题以及解决该问题的一种方法。事实上,一个具有许多分支的外部crate中枚举的match
触发了对dry
的初始开发!seq_macro
:启发了在macro_for!
中使用的语法。如果你想在编译时迭代一系列数值或字符值而不是令牌列表,这是一个很好的选择。
许可证
dry
根据MIT许可证和Apache 2.0许可证进行许可,由您选择。
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交的工作中的任何贡献,都应如上所述进行双重许可,不附加任何额外条款或条件。
贡献
如果您想看到任何东西被修复或添加,请打开一个pull request,或者如果您不确定如何开始,请创建一个问题。
通往1.0的道路
- 类似
for
的语法。 - 有用的编译器错误信息和提示,模仿rustc的等效运行时构造的错误。
- 用于宏调用非法的包装器(例如,结构体字段、枚举案例、匹配分支):
macro_wrap
。 - 修复在最后一个
}
之后添加内容被忽略的bug。应该是一个错误。 - 更好的文档
- 测试
- 支持使用类似元组解构的语法支持多个替换变量
- 支持在替换中包含逗号,通过括号包装(并支持括号,通过双写它们)
- 确定最小Rust版本
- 使用作用域替换变量进行嵌套(目前替换变量是向外展开,而不是像在常规
for
循环中期望的向内展开) -
macro_let
宏用于惯用替换(在不需要语法参数的情况下替换macro_rules!
) - 调查在循环体中将替换与语法元素连接起来?例如标识符(
$variable~_suffix
),或运算符(variable $op~= change
)。这旨在简单情况下作为macro_rules!
的直接替代。它如何解决这个问题?参见paste
crate。 macro_wrap
是否也能在 crate 外部展开宏?可能不行,但让我们调查一下。也许如果我们不能自动执行它,我们可以让其他宏 crate 插入其中。- 如何处理具有重复项目组的替换?
duplicate
通过他们所说的 参数化替换 解决了这个问题
依赖关系
~140KB