我有一个宏,它接受一个函数声明列表,并将它们转换为不同的声明.
macro_rules! re_export {
($(pub fn $i:ident($($arg:ident: $argty:ty)*) -> $ret:ty;)*) => ($(
extern {
pub fn $i($($arg: $argty),*) -> $ret;
}
)*);
($(pub fn $i:ident($($arg:ident: $argty:ty)*);)*) => ($(
extern {
pub fn $i($($arg: $argty),*);
}
)*);
}
Run Code Online (Sandbox Code Playgroud)
使用方式如下:
re_export! {
pub fn abs(i: c_int) -> c_int;
pub fn rand() -> c_int;
pub fn foo();
pub fn add(i: c_int, j: c_int) -> c_int;
}
Run Code Online (Sandbox Code Playgroud)
我如何概括宏,以便我可以给它带有或不带args和返回类型的多个函数,让它适用于所有这些函数.很容易制作一个适用于同一类型的几个函数的宏,但我无法弄清楚如何使它适用于不同类型.
DK.*_*DK. 11
嗯,有两种方法.
如果要解析这种确切的语法,则需要使用muncher.所以,像:
macro_rules! re_export {
() => {};
(
pub fn $i:ident($($arg:ident: $argty:ty)*) -> $ret:ty;
$($tail:tt)*
) => {
extern {
pub fn $i($($arg: $argty),*) -> $ret;
}
re_export! { $($tail)* }
};
(
pub fn $i:ident($($arg:ident: $argty:ty)*);
$($tail:tt)*
) => {
extern {
pub fn $i($($arg: $argty),*);
}
re_export! { $($tail)* }
};
}
Run Code Online (Sandbox Code Playgroud)
这涉及一次断开一个函数签名,递归处理它们.这是解析事物的最灵活方式,但确实意味着您可以遇到宏递归限制.默认限制为64,因此如果您有更多输入,则需要多个顶级宏调用,或者您必须通过向包中添加#![recursion_limit="128"]
属性来手动提高递归限制.
另一种是更改语法,以便您拆分然后分两步处理签名.为此,您必须为签名提供某种常规顶级语法.例如:
macro_rules! re_export {
($({$($sigs:tt)*})*) => {
$(
re_export! { @fn $($sigs)* }
)*
};
(@fn pub fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty) => {
extern {
pub fn $i($($arg: $argty),*) -> $ret;
}
};
(@fn pub fn $i:ident($($arg:ident: $argty:ty),*)) => {
extern {
pub fn $i($($arg: $argty),*);
}
};
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们将每个函数签名包装在{...}
s中.这是因为匹配器组((...)
,[...]
和{...}
)允许macro_rules!
盲目匹配其内容,而不必理解它们.这允许我们以常规方式匹配不规则函数签名.顶级扩展只是将每个单独的功能签名转发回自身以进行实际处理.这@fn
只是一个内部规则标记,以确保我们在递归过程中选择正确的规则.
这与前一个没有相同的递归限制...但要求您使用稍微钝的语法:
re_export! {
{ pub fn abs(i: c_int) -> c_int }
{ pub fn rand() -> c_int }
{ pub fn foo() }
{ pub fn add(i: c_int, j: c_int) -> c_int }
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
408 次 |
最近记录: |