如何在声明性宏中提前 return 并推断 return 类型?

How do I early return in declarative macros and infer the return type?

我有一个宏,它只生成一个结构的实例,如下所示:

macro_rules! foo {
    () => {{
        let baz_val = baz();
        
        let bar_val = match bar() {
            Ok(val) => val,
            Err(err) => {
                return Err(err);
            }
        };
        
        Ok(Foo(baz_val, bar_val))
    }};
}

如您所见,我根据 bar() 函数的结果在宏中做了一个早期的 return。然而,这是一个错误,说:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:23:24
   |
23 |                 return Err(err);
   |                        ^^^^^^^^ expected `()`, found enum `Result`
...
32 |     let foo_val = foo!();
   |                   ------ in this macro invocation
   |
   = note: expected unit type `()`
                   found enum `Result<_, String>`
   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.

Here's also the permalink to the playground 具有完整的最小可重现样本。

我认为这里的问题是类型推断。我想 return 示例中 FooResult 的实例,但宏无法推断它。

那么,如何在声明性宏中提前 return 和 infer/define 输入 return?


环境

return 用于函数而不是宏。对于预期的行为,您可以将宏包装到闭包中并立即调用它:

macro_rules! foo {
    () => {{
        (|| {
        let baz_val = baz();

        let bar_val = match bar() {
            Ok(val) => val,
            Err(err) => {
                return Err(err);
            }
        };

        Ok(Foo(baz_val, bar_val))
        })()

    }};
}

Playground

@Netwave 的答案的另一种选择是使用夜间专用功能 label-break-value,如下所示:

#![feature(label_break_value)]

macro_rules! foo {
    () => {'foo: {
        let baz_val = baz();

        let bar_val = match bar() {
            Ok(val) => val,
            Err(err) => {
                break 'foo Err(err);
            }
        };

        Ok(Foo(baz_val, bar_val))
    }};
}

Playground

我相信这个功能被明确设计为能够从任意块“return”,这几乎是你的情况。