gpt4 book ai didi

macros - 编写包含匹配主体的宏

转载 作者:行者123 更新时间:2023-11-29 08:23:05 24 4
gpt4 key购买 nike

我正在尝试压缩一些具有类似于以下结构的重复代码:

match self.foo() {
None => self.bar(),
Some(MyStruct { foo: x, .. }) => match x {
Pattern1 => result,
Pattern2 => {
block_result
}
}
}

我想这样写:

my_macro!(
Pattern1 => result,
Pattern2 => {
block_result
}
)

避免重复的None 处理和MyStruct 解构。

这看起来应该很简单,因为它本质上只是将宏主体替换为匹配表达式,但我实际上看不到任何方法可以做到这一点。

我尝试按如下方式编写宏:

macro_rules! my_macro (
($($pat:pat => $result:expr,)*) => (
match self.foo() {
None => self.bar(),
Some(MyStruct { foo: x, .. }) => match x {
$(
$pat => $result,
)*
},
}
);
)

但这失败了,因为匹配臂的 RHS 可以是表达式或 block (并且它也不处理可选地省略最后一个臂的逗号)。据我所知,没有办法指定宏模式的一部分可以是 block 或表达式,所以我想不出解决这个问题的方法。

理想情况下,我想这样做而不必编写复杂的模式来破坏匹配主体,只是为了将它们重新粘在一起,但我认为没有任何指示符可以接受匹配表达式的主体。

你会如何编写这个宏?甚至可以不编写编译器插件吗?

最佳答案

我不知道你为什么这么决定

this fails, as the RHS of a match arm can be an expression or a block

在 Rust 中,匹配臂总是表达式,恰好 block 也是表达式。

您的宏中有两个问题。首先,正如您所注意到的,您的宏不会处理省略最后一个逗号的问题。这可以很容易地补救:您只需更改此模式:

$($pat:pat => $result:expr,)*

进入这个:

$($pat:pat => $result:expr),*

它的用法也应该改变:

             $(
$pat => $result,
)*

             $(
$pat => $result
),*

第二个问题是,除非你在包含 self 标识符的范围内定义这个宏(即在方法内部),否则它不会像你期望的那样工作,因为卫生 - 您在 self.foo()self.bar() 调用中使用的 self 标识符在宏主体中将与宏扩展站点中的不同.作为一般规则,您始终需要将要在宏扩展站点上使用的标识符作为参数传递给宏,除非该宏是在这些标识符已经存在的范围内定义的。

因此,宏的最终变体是这样的:

macro_rules! my_macro (
($_self:expr, $($pat:pat => $result:expr),*) => (
match $_self.foo() {
None => $_self.bar(),
Some(MyStruct { foo: x, .. }) => match x {
$(
$pat => $result
),*
},
}
);
)

它确实可以如您所愿地工作。

您可以找到有关宏及其编写方法的更多信息 in the official guide .

关于macros - 编写包含匹配主体的宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27329653/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com