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

Hen*_*nry 6 macros rust

我正在创建一个名为 的宏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

...
Run Code Online (Sandbox Code Playgroud)

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

错误:

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
Run Code Online (Sandbox Code Playgroud)

这些错误的原因是什么以及如何修复它?

kmd*_*eko 3

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

#[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!(),
            }
        } // <-------------------
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 您可以直接使用绝对路径(即 `::crate_name::some_path::RaptorexError`),也可以在块内使用 `use` 声明。 (2认同)