使用 Rust 宏简化“匹配”
Simplifying a `match` using a Rust macro
问题函数有很多(数百个),每个函数可能有不同的类型。对于每个问题,我想 运行 一个 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 的书,但是宏的例子并不多。
我该怎么做?
我只是复制了 match
语句,而不是许多 if
语句
对所有可用分支重复 $( ... )*
。
它似乎表现得像广泛的 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.");
}
}
};
}
错误信息解释:
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.")
};
问题函数有很多(数百个),每个函数可能有不同的类型。对于每个问题,我想 运行 一个 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 的书,但是宏的例子并不多。
我该怎么做?
我只是复制了 match
语句,而不是许多 if
语句
对所有可用分支重复 $( ... )*
。
它似乎表现得像广泛的 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.");
}
}
};
}
错误信息解释:
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.")
};