Simplifier une `correspondance` en utilisant une macro Rust
Il existe de nombreuses fonctions de questions (des centaines), et chacune peut avoir un type différent. Pour chaque question, je veux exécuter une run_questionfonction, qui montre combien de temps cette fonction a pris et imprimer sa sortie.
J'essaie de raccourcir l' matchexpression suivante avec une macro Rust (écrire des run_questioncentaines de fois rend le code assez long):
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.");
},
}
}
Je n'ai aucune expérience dans l'écriture de macros et j'ai essayé ce qui suit qui ne fonctionne pas exactement. Cela donne l'erreur:
error: variable 'question_num' is still repeating at this depth
Je suis également assez perplexe quant à la façon dont je peux imprimer le Question doesn't exist.cas par défaut.
#[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);
}
}
};
}
La façon dont j'aimerais l'utiliser est (ou tout ce qui est aussi court, c'est bien aussi):
run_questions!(question_num, 1, q1, 2, q2, 3, q3, 4, q4);
J'ai lu un peu le livre Rust, mais il n'y a pas exactement autant d'exemples de macros.
Comment pourrais-je procéder?
Réponses
Plutôt que de nombreuses ifdéclarations, je viens de reproduire la matchdéclaration avec une répétition $( ... )*pour toutes les branches disponibles. Il semble se comporter comme l' matchexpression extensive .
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.");
}
}
};
}
Le message d'erreur expliqué:
macro_rules! run_questions {
($chosen_question: expr, $($question_num: expr, $question_mod: expr),*) => {{
Dans le modèle ci-dessus, vous avez une répétition avec l' *opérateur qui implique des variables $question_numet$question_mod
if $chosen_question == $question_num {
run_question($question_mod::solve);
}
Dans le code correspondant, vous ne pouvez pas utiliser $question_numet $question_moddirectement: comme ils sont répétés, ils ont potentiellement plus d'une valeur et laquelle doit utiliser le compilateur ici? Au lieu de cela, vous devez dire au compilateur de répéter le bloc de code qui utilise ces variables. Cela se fait en entourant le bloc de code répété $()et en ajoutant l' *opérateur:
$(if $chosen_question == $question_num { run_question($question_mod::solve);
})*
Bien que comme indiqué par la réponse de @ prog-fh, il vaut mieux utiliser a matchdans la macro, comme dans le code simple:
match $chosen_question { $($question_num => run_question ($question_mod::solve),)*
_ => println!("Question doesn't exist.")
};