macro_rules! macro_once {
(
$(#[$attr:meta])* macro $name:ident ( $($pattern:tt)* ) {
$($body:tt)*
}
$($usage:tt)*
) => { ... };
(
$(#[$attr:meta])* macro $name:ident {
$(
( $($pattern:tt)* ) => { $($body:tt)* } $(;)?
)*
}
$($usage:tt)*
) => { ... };
(
$(#[$attr:meta])* macro ( $($pattern:tt)* ) => {
$($body:tt)*
}
$($usage:tt)*
) => { ... };
(
$(#[$attr:meta])*
macro => { $(
( $($pattern:tt)* ) => { $($body:tt)* } $(;)?
)*
}
$($usage:tt)*
) => { ... };
}Expand description
§立即宏
- 🎯在一些非常专用的地方节省代码
- 🎯在定义宏但其不能通用的情况节省认知负担
- 🚩定义一次宏,然后立即 使用/调用/消耗 它
- ✨对「一次性表达式」可匿名
- ✨若为「条目宏」,其后仍然可以导出
- 📌对匿名宏的卫生性保证
- ✅基于
macro_rules的卫生性,使用该宏定义的「一次性匿名宏」不会占用已有标识符
- 🚩对于匿名宏,要调用自身,可使用标识符
_self(硬编码)
- ✅基于
macro_rules的可见性,使用该宏定义的「一次性匿名宏」不会泄漏到其它模块
- 💭亦可选择性泄漏:属性宏
#[macro_export]
§作为 语句/条目(函数定义、多行代码…)
use nar_dev_utils::macro_once;
macro_once! {
macro 一次性宏名称( ) {
}
}
§作为 表达式
use nar_dev_utils::macro_once;
macro_once! {
macro ( ) => {
}
}
§测试用例
use nar_dev_utils::macro_once;
use nar_dev_utils::asserts;
const ONE: usize = macro_once! {
macro () => { 1 }
};
assert_eq!(ONE, 1);
let mut x = 0_i32;
macro_once! {
macro plus_one($var:ident) {
$var += 1;
}
x
}
assert_eq!(x, 1);
macro_once! {
macro plus(
$arg_ty:ty;
$( $name:ident => [$($arg:ident)*]; )*
) {
$( fn $name($($arg: $arg_ty),*) -> $arg_ty { 0 $(+ $arg)* } )*
}
i32;
plus_0 => [];
plus_1 => [a];
plus_2 => [a b];
plus_3 => [a b c];
}
assert_eq!(plus_0(), 0);
assert_eq!(plus_1(1), 1);
assert_eq!(plus_2(1, 2), 3);
assert_eq!(plus_3(1, 2, -3), 0);
macro_rules! macro_anonymous {
($a:expr) => {
$a + 2
};
}
assert_eq!(
macro_once! {
macro ($a:expr) => {$a + 1}
1 + 1
},
3
);
macro_once! {
macro asserts_plus($( $($num:expr)* => $sum:expr; )*) {
$( assert_eq!(0 $(+ $num)*, $sum); )*
}
1 2 => 3;
1 3 => 4;
2 2 => 4;
2 3 => 5;
}
assert_eq!(
macro_anonymous! {
2
},
4
);
macro_once! {
#[macro_export]
macro multi_dispatch {
( $( $name:ident => $arg:tt; )* ) => {
$(
multi_dispatch! {
$name = $arg
}
)*
}
( let $name:ident $value:expr ) => {
let $name = $value;
}
( $name:ident = 1 ) => {multi_dispatch! {let $name 1} }
( $name:ident = 2 ) => {multi_dispatch! {let $name 2} }
( $name:ident = 3 ) => {multi_dispatch! {let $name 3} }
( $name:ident = $unknown:expr ) => {multi_dispatch! {let $name 0} }
}
a => 1;
b => 2;
c => 3;
d => 4;
}
assert_eq!(a + b + c, 6);
assert_eq!(d, 0);
let tuple = macro_once! {
macro => {
( $( { $($value_ex:tt)* } $(,)? )* ) => { ( $( _self! { @ $($value_ex)* } ),* ) }
(@ ) => { () }
(@ $a:literal plus $b:literal ) => { $a + $b }
(@ $a:literal times $b:literal ) => { $a + $b }
(@ stringify! $($token:tt)* ) => { stringify!($($token)*) }
(@ rust $e:expr ) => { $e }
}
{1_i32 plus 2_i32},
{},
{2_i32 times 2_i32},
{stringify! <{SELF} --> [good]>.}
{rust {
let mut s = String::new();
s += "123";
assert_eq!(s, "123");
s
}}
};
let _: &(i32, (), i32, &str, String) = &tuple;
asserts! {
tuple.0 == 3
tuple.2 == 4
tuple.3 == "<{ SELF } --> [good]>."
tuple.4 == "123"
}