9 个版本
0.3.3 | 2023 年 10 月 12 日 |
---|---|
0.3.2 | 2023 年 8 月 5 日 |
0.3.1 | 2023 年 7 月 29 日 |
0.3.0 | 2023 年 6 月 22 日 |
0.1.1 | 2023 年 3 月 19 日 |
#427 在 Rust 模式
每月 37 次下载
13KB
82 行
纳德
英文 | 简体中文
nade
是一个属性宏,用于为 Rust 函数添加命名和默认参数。
用法
// some_crate/src/lib.rs
pub use nade::base::*;
use nade::nade;
pub fn one() -> u32 {
1
}
#[nade]
pub fn foo(
/// You can add doc comments to the parameter. It will be shown in the doc of the macro.
///
/// The world is 42.
#[nade(42)] a: u32,
/// Call a function
#[nade(one())] b: u32,
/// Default value of u32
#[nade] c: u32,
d: u32
) -> u32 {
a + b + c + d
}
assert_eq!(foo!(1, 2, 3, 4), 10); // foo(1, 2, 3, 4)
assert_eq!(foo!(d = 2), 45); // foo(42, one(), Default::default(), 2)
assert_eq!(foo!(1, c = 2, b = 3, 4), 10); // foo(1, 3, 2, 4)
工作原理
如果你编写了一个像这样的函数
// some_crate/src/lib.rs
pub use nade::base::*;
use nade::nade;
pub fn one() -> u32 {
1
}
#[nade]
pub fn foo(
#[nade(42)]
a: u32,
#[nade(one())]
b: u32,
#[nade]
c: u32,
d: u32
) -> u32 {
a + b + c + d
}
它将被扩展为
// some_crate/src/lib.rs
// ⓵
pub use nade::base::*;
use nade::nade;
pub fn one() -> u32 {
1
}
pub fn foo(a: u32, b: u32, c: u32, d: u32) -> u32 {
a + b + c + d
}
// ⓶
#[::nade::__internal::macro_v(pub)]
macro_rules! foo {
($($arguments:tt)*) => {
// ⓷
$crate::nade_helper!(
($($arguments)*)
(a: u32 = 42, b: u32 = one(), c: u32 = Default::default(), d: u32)
(foo)
)
};
}
然后,当你像这样调用宏 foo
时
use some_crate::{foo, one};
foo!(32, d = 1, c = 2);
它将被扩展为
use some_crate::{foo, one};
foo(32, one(), 2, 1);
注意
如工作原理中所示,在 #[nade]
生成的代码中,有 3 件事情需要注意。
-
⓵, ⓷
nade_helper
是一个声明式宏,用于基于参数、参数和函数路径生成函数调用表达式。它的路径默认为
$crate::nade_helper
,因此您需要使用pub use nade::base::*;
或pub use nade::base::nade_helper;
在 crate 的根目录中导入宏。您还可以自定义
nade_helper
的路径。use nade::nade; mod custom_nade_helper { pub use nade::base::nade_helper; } #[nade] #[nade_path(nade_helper = custom_nade_helper)] fn custom_nade_helper_path(a: usize) -> usize { a }
-
⓶
macro_v
是一个属性宏,使声明式宏的可见性与函数相同。有关详细信息,请参阅 macro-v。它的路径默认为
::nade::__internal::macro_v
。您还可以自定义
macro_v
的路径。use nade::nade; mod custom_macro_v { pub use nade::__internal::macro_v; } #[nade] #[nade_path(macro_v = custom_macro_v)] fn custom_macro_v_path(a: usize) -> usize { a }
限制
-
当你调用宏
foo
时,你必须使用use
语句将宏引入作用域。// Good use some_crate::{foo, one}; foo!(32, d = 1, c = 2); // Bad use some_crate::one; some_crate::foo!(32, d = 1, c = 2);
因为属性宏
#[nade]
将生成与函数同名的新宏,并且该宏以不卫生的方式使用该函数,所以你必须使用use
语句来将宏和函数引入作用域。 -
默认参数表达式必须导入到宏调用的作用域中。
// Good use some_crate::{foo, one}; foo!(32, d = 1, c = 2); // Bad use some_crate::foo; foo!(32, d = 1, c = 2);
因为默认参数表达式是在
#[nade]
宏展开之后评估的,所以它必须导入到宏调用的作用域中。
如何绕过限制
-
你可以为函数上的
#[nade]
属性宏传递以$crate
开头的模块路径。#[nade(module_path = $crate::module)] // <--- here pub fn foo( #[nade(42)] a: u32, #[nade(one())] b: u32, #[nade] c: u32, d: u32 ) -> u32 { a + b + c + d }
它将被扩展为
pub fn foo(a: u32, b: u32, c: u32, d: u32) -> u32 { a + b + c + d } #[::nade::__internal::macro_v(pub)] macro_rules! foo { ($($arguments:tt)*) => { $crate::nade_helper!( ($($arguments)*) (a: u32 = 42, b: u32 = one(), c: u32 = Default::default(), d: u32) ($crate::module::foo) // <--- here ) }; }
然后,你不需要使用
use
语句来将宏和函数引入作用域,如下所示use some_crate::one; some_crate::foo!(32, d = 1, c = 2);
-
在参数的
#[nade]
属性宏中,你可以使用完整路径指定默认参数表达式,无论是$crate::a::expr
,还是::a::b::expr
。实际上,当你在参数上使用#[nade]
时,你实际上是在使用#[nade(::core::default::Default::default())]
.pub fn one() -> u32 { 1 } pub static PATH: &str = "a"; #[nade] pub fn foo<T1, T2, T3, T4>( #[nade($crate::module::one())] a: T1, #[nade(::std::path::Path::new("a"))] b: T2, #[nade($crate::module::PATH)] c: T3, #[nade("Hello")] d: T4 ) { let _ = (a, b, c, d); }
它将被扩展为
pub fn foo<T1, T2, T3, T4>(a: T1, b: T2, c: T3, d: T4) { let _ = (a, b, c, d); } #[::nade::__internal::macro_v(pub)] macro_rules! foo { ($($arguments:tt)*) => { $crate::nade_helper!( ($($arguments)*) ( a: T1 = $crate::module::one(), b: T2 = ::std::path::Path::new("a"), c: T3 = $crate::module::PATH, d: T4 = "Hello", ) (foo) ) }; }
然后,你不需要使用
use
语句来将默认参数表达式引入作用域,如下所示use some_crate::foo; foo!();
致谢
这个 crate 受以下 crate 启发
依赖
~0.5–1MB
~24K SLoC