如何在宏中调用自身的方法?
How to call methods on self in macros?
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-nightly。
Rust 宏不仅仅是文本替换。相反,有几个重要的区别,其中之一是 "macro hygiene"。有了这个,宏内部的标识符不会干扰外部的标识符,这确实可以防止一些通常发生在像 C 的宏系统中的错误。
因此,宏只能访问以下标识符:
- 明确通过,或
- 定义宏时在范围内。
虽然乍一看这似乎是一个不必要的限制,但它实际上有助于提高代码的可读性。否则,它是 "spooky action at a distance"。在 Rust 中通过 some_fn(&mut foo)
将对变量的引用传递给函数的原因或多或少是相同的,而不是像 C++ 中那样隐式(some_fn(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);
}
}
这两者也有有趣的组合,比如定义一个显式接受 self
的宏,并在函数内部定义另一个宏来捕获 self
:
macro_rules! call_on_self_outer {
($self:ident, $F:ident) => {
$self.$F()
};
}
struct F;
impl F {
fn dummy(&self) {}
fn test(&self) {
macro_rules! call_on_self {
($F:ident) => {
call_on_self_outer!(self, $F);
};
}
call_on_self!(dummy);
}
}
`
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-nightly。
Rust 宏不仅仅是文本替换。相反,有几个重要的区别,其中之一是 "macro hygiene"。有了这个,宏内部的标识符不会干扰外部的标识符,这确实可以防止一些通常发生在像 C 的宏系统中的错误。
因此,宏只能访问以下标识符:
- 明确通过,或
- 定义宏时在范围内。
虽然乍一看这似乎是一个不必要的限制,但它实际上有助于提高代码的可读性。否则,它是 "spooky action at a distance"。在 Rust 中通过 some_fn(&mut foo)
将对变量的引用传递给函数的原因或多或少是相同的,而不是像 C++ 中那样隐式(some_fn(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);
}
}
这两者也有有趣的组合,比如定义一个显式接受 self
的宏,并在函数内部定义另一个宏来捕获 self
:
macro_rules! call_on_self_outer {
($self:ident, $F:ident) => {
$self.$F()
};
}
struct F;
impl F {
fn dummy(&self) {}
fn test(&self) {
macro_rules! call_on_self {
($F:ident) => {
call_on_self_outer!(self, $F);
};
}
call_on_self!(dummy);
}
}
`