如何在 `macro_rules!` 中声明一个变量?

How to declare a variable in `macro_rules!`?

我正在创建一个名为 throw_error 的宏。我希望它能编译,但它失败了:

// Util structs + types

...

// Util macros

#[macro_export]
macro_rules! throw_error {
    () => {
        RaptorexError {
            message: String::new(),
            line: line!(),
            file: file!().to_owned(),
        }
    };

    ($($msg:tt),*) => {
        let mut final_msg = String::new();

        $(
            final_msg.push_str(&format!("{} ", $msg));
        )*

        // remove trailing whitespace
        final_msg.pop();

        RaptorexError {
            message: final_msg,
            line: line!(),
            file: file!(),
        }
    }
}

// Util functions

...

我在其他代码中使用宏时遇到了几个错误。

错误:

error: macro expansion ignores token `final_msg` and any following
  --> /Users/henryboisdequin/Desktop/raptorex/raptorex_util/src/lib.rs:30:13
   |
30 |             final_msg.push_str(&format!("{} ", $msg));
   |             ^^^^^^^^^
   | 
  ::: compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ------------------------------------------------- help: you might be missing a semicolon here: `;`
   |                             |
   |                             caused by the macro expansion here
   |
   = note: the usage of `throw_error!` is likely invalid in expression context

error[E0658]: `let` expressions in this position are experimental
  --> compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
   = help: add `#![feature(let_chains)]` to the crate attributes to enable
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: `let` expressions are not supported here
  --> compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: only supported directly in conditions of `if`- and `while`-expressions
   = note: as well as when nested within `&&` and parenthesis in those conditions
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused imports: `DATA_TYPES`, `KEYWORDS`
 --> compiler/src/parser/parser.rs:3:28
  |
3 |     lexer::tokens::{Token, DATA_TYPES, KEYWORDS},
  |                            ^^^^^^^^^^  ^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0308]: mismatched types
  --> compiler/src/parser/parser.rs:44:29
   |
44 |             _ => return Err(throw_error!("Unexpected token:", current_token)),
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `raptorex_util::RaptorexError`, found `bool`
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 4 previous errors; 1 warning emitted

这些错误的原因是什么,我该如何解决?

您需要另一组 {},以便宏创建一个包含语句而不是单个语句本身的块:

#[macro_export]
macro_rules! throw_error {
    () => {
        RaptorexError {
            message: String::new(),
            line: line!(),
            file: file!().to_owned(),
        }
    };

    ($($msg:tt),*) => {
        { // <------------------
            let mut final_msg = String::new();
    
            $(
                final_msg.push_str(&format!("{} ", $msg));
            )*
    
            // remove trailing whitespace
            final_msg.pop();
    
            RaptorexError {
                message: final_msg,
                line: line!(),
                file: file!(),
            }
        } // <-------------------
    }
}

(...) => {} 中的 {} 是宏语法的一部分,不是生成代码的一部分。