macro_rules! call_on_self {
($F:ident) => {
self.$F()
}
}
struct F;
impl F {
fn dummy(&self) {}
fn test(&self) {
call_on_self!(dummy);
}
}
以上不起作用(Playground):
error[E0424]: expected value, found module `self`
--> src/lib.rs:3:9
|
3 | self.$F()
| ^^^^ `self` value is a keyword only available in methods with `self` parameter
...
11 | call_on_self!(dummy);
| --------------------- in this macro invocation
我不明白为什么这不起作用:在self
可用的方法中调用宏!这有点可能吗?我是否应该将self
传递给宏,否则宏无法解析self
?
我每晚使用rustc 1.19.0。
答案 0 :(得分:8)
Rust宏不仅仅是文本替换。相反,存在一些重要的差异,其中之一是“宏观卫生”。有了这个,宏中的标识符不会干扰外部的标识符,这可以防止像C这样的宏系统经常发生的一些错误。
因此,宏只能访问以下标识符:
虽然它看起来似乎是一个不必要的限制,但实际上它有助于代码的可读性。否则,它是“远距离的怪异行动”。这或多或少是相同的原因,为什么将变量的引用传递给函数是通过Rust中的&mut foo
完成的,并不像C ++(foo
)那样隐式:因为那时,它已经清楚了变量如何变量由呼叫站点的功能使用。
这意味着我们有两种方法可以解决您的问题。标准解决方案是将self
传递给宏:
macro_rules! call_on_self {
($self:ident, $F:ident) => {
$self.$F()
}
}
struct F;
impl F {
fn dummy(&self) {}
fn test(&self) {
call_on_self!(self, dummy);
}
}
如果您只需要在test
方法中使用宏,则可以在该方法中定义宏。然后,self
在定义宏时已经在范围内,因此它可以在不传递self
的情况下工作:
struct F;
impl F {
fn dummy(&self) {}
fn test(&self) {
macro_rules! call_on_self {
($F:ident) => {
self.$F()
}
}
call_on_self!(dummy);
}
}