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

标签 rust macros

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

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

最佳答案

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

#[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!(),
            }
        } // <-------------------
    }
}

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

关于rust - 如何在 `macro_rules!` 中声明一个变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66240468/

相关文章:

rust - 列表中相同索引项的并行迭代 |语法问题

ios - 更清洁的 XCode 宏

C 宏使用文字与变量产生不同的结果

c++ - 宏重新定义

c - 我如何在 C 中进行这种巧妙的转换?

rust - 如何返回包含 serde_json::Value 的结果?

rust - _ 在 Rust 中的类型错误中意味着什么?

rust - 在 Rust 中创建动态二维数组的正确语法是什么?

pointers - 将 &[T] 类型的输入向量转换为 Vec<T>

macros - 如果 Lisp 中的宏是一元的,这意味着什么?