Macros 如何在不同类型的函数上泛化Rust宏?
我有一个宏,它接受函数声明列表,并将它们转换为不同的声明Macros 如何在不同类型的函数上泛化Rust宏?,macros,rust,Macros,Rust,我有一个宏,它接受函数声明列表,并将它们转换为不同的声明 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
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),*);
}
)*);
}
它是这样使用的:
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;
}
如何对宏进行泛化,使其具有或不具有参数和返回类型的多个函数,并使其能够处理所有这些函数。制作一个可以在同一类型的多个函数上工作的宏很容易,但我不知道如何使它在不同类型上工作。嗯,有两种方法 如果您想解析这个确切的语法,那么您需要使用一个。比如说:
macro\u规则!再出口{
() => {};
(
发布fn$i:ident($($arg:ident:$argty:ty)*)->$ret:ty;
$($tail:tt)*
) => {
外行{
发布fn$i($($arg:$argty),*)->$ret;
}
再出口!{$($tail)*}
};
(
发布fn$i:ident($($arg:ident:$argty:ty)*);
$($tail:tt)*
) => {
外行{
发布fn$i($($arg:$argty),*);
}
再出口!{$($tail)*}
};
}
这涉及到一次中断一个函数签名,递归地处理它们。这是最灵活的解析方式,但确实意味着您可能会遇到宏递归限制。默认限制为64,因此,如果输入多于64,则需要多次顶级宏调用,或者必须通过添加#手动提高递归限制![recursion\u 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),*);
}
};
}
这里,我们将每个函数签名包装在{…}
s中。这是因为匹配器组((…)
、[…]
和{…}
)允许宏规则代码>盲目地匹配它们的内容,而不必理解它们。这允许我们以常规方式匹配不规则函数签名。顶级扩展只是将每个单独的函数签名转发回自身进行实际处理。@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 }
}
我会根据你的用户名假设你写了你链接的那本书。非常好!我希望谷歌在我研究这个问题时能给我建议一下。