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.

推荐答案

Rust宏不仅仅是文本替换.相反,这里有两个重要的区别,其中一个是"宏观卫生".这样一来,宏内部的标识符就不会与外部的标识符发生冲突,这就防止了C等宏系统中常见的一些错误.

因此,宏只能访问以下标识符:

  • 明确通过,or
  • 定义宏时,在范围内.

虽然一开始它似乎是一个不必要的限制,但实际上它有助于提高代码的可读性.否则,这就是"远处的恐怖行动".这或多或少是相同的推理,为什么将变量引用到函数中是通过some_fn(&mut foo)的Rust 来完成的,而不是在C++(some_fn(foo))中隐含的:在调用站点中函数如何使用变量更清楚.

这意味着我们有两种方法来解决您的问题.标准溶液为pass in 100 to the macro:

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方法中使用宏,可以使用define the macro inside that method.然后,定义宏时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);
    }
}
`

Rust相关问答推荐

如何在rust中有条件地分配变量?

如何访问Rust存储值的内存地址

为什么实例方法可以像Rust中的静态方法一样被调用?

在铁 rust 中传递所有权

当对VEC;U8>;使用serde_json时,Base64编码是保护空间的好方法吗?

无法将 rust 蚀向量附加到另一个向量

如何初始化选项<;T>;数组Rust 了?

处理带有panic 的 Err 时,匹配臂具有不兼容的类型

找不到 .has_func 或 .get_func 的 def

为什么编译器看不到这个 `From` impl?

Rust 如何返回大类型(优化前)?

Rust 中指向自身的引用如何工作?

返回优化后的标题:返回异步块的闭包的类型擦除

为什么 Rust 的临时值有时有参考性有时没有?

n 个范围的笛卡尔积

如何使返回 XMLError 的方法与 anyhow::Error 兼容?

只有一个字符被读入作为词法分析器的输入

提取 struct 生成宏中字段出现的索引

如何重写这个通用参数?

来自外部函数的future 内部可变引用