【问题标题】:Simplifying a `match` using a Rust macro使用 Rust 宏简化“匹配”
【发布时间】:2020-09-17 14:38:16
【问题描述】:

有许多问题功能(数百个),并且每个可能有不同的类型。对于每个问题,我想运行一个run_question 函数,它显示该函数花费了多长时间,并打印它的输出。

我正在尝试使用 Rust 宏缩短以下 match 表达式(编写 run_question 100 次确实会使代码相当长):

fn run_question<T: std::fmt::Display>(question_func: fn() -> T) {
  let begin = Instant::now();
  let output: T = question_func();
  let elapsed_secs = begin.elapsed().as_micros() as f32 / 1e6;
  println!("{}", output);
  println!("{:.6}s taken", elapsed_secs);
}

fn q1() -> u8 { /* ... */ }
fn q2() -> u32 { /* ... */ }
fn q3() -> u64 { /* ... */ }
fn q4() -> String { /* ... */ }

fn main() {
  // ...
  match question_num {
    1 => run_question(q1), 2 => run_question(q2), 3 => run_question(q3), 4 => run_question(q4),
    _ => {
      println!("Question doesn't exist.");
    },
  }
}

我没有编写宏的经验,并尝试了以下不完全有效的方法。它给出了错误:

error: variable 'question_num' is still repeating at this depth

我也很困惑如何将Question doesn't exist. 作为默认情况打印。

#[macro_export]
macro_rules! run_questions {
  ( $chosen_question: expr, $( $question_num: expr, $question_mod: expr ), * ) => {
    {
      if $chosen_question == $question_num {
        run_question($question_mod::solve);
      }
    }
  };
}

我想使用它的方式是(或者任何一样短的都可以):

run_questions!(question_num, 1, q1, 2, q2, 3, q3, 4, q4);

我读了一些 Rust 书,但没有那么多宏示例。

我该怎么做呢?

【问题讨论】:

  • 你会考虑其他选择吗?

标签: rust macros


【解决方案1】:

而不是很多if声明,我只是转载了match声明 对于所有可用的分支,重复$( ... )*。 它的行为似乎类似于广泛的 match 表达式。

macro_rules! run_questions {
    ( $chosen_question: expr, $( $question_num: expr, $question_mod: expr ), * ) => {
        match $chosen_question {
          $($question_num => run_question($question_mod),)*
          _ => {
                println!("Question doesn't exist.");
          }
        }
    };
}

【讨论】:

    【解决方案2】:

    错误信息解释:

    macro_rules! run_questions {
        ($chosen_question: expr, $($question_num: expr, $question_mod: expr),*) => {{
    

    在上述模式中,您重复使用 * 运算符,其中涉及变量 $question_num$question_mod

            if $chosen_question == $question_num {
                run_question($question_mod::solve);
            }
    

    在相应的代码中,您不能直接使用$question_num$question_mod:因为它们是重复的,它们可能具有多个值,编译器应该在这里使用哪一个?相反,您需要告诉编译器重复使用这些变量的代码块。这是通过用$() 包围重复的代码块并添加* 运算符来完成的:

            $(if $chosen_question == $question_num {
                run_question($question_mod::solve);
            })*
    

    尽管正如@prog-fh 的回答所指出的,最好在宏中使用match,与直接代码中的相同:

    match $chosen_question {
        $($question_num => run_question ($question_mod::solve),)*
        _ => println!("Question doesn't exist.")
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-16
      • 2019-01-26
      • 1970-01-01
      相关资源
      最近更新 更多