为了学习Rust,我已经开始实现Project Euler的一些问题了。现在我想采取下一步并创建一个基于控制台的用户界面,该界面能够运行所有或仅特定的问题。另一个要求是用户应该只能将可选参数传递给特定问题。
我目前的解决方案是让一个Trait ProjectEulerProblem
声明例如run()
。有了这个,我可以这样做:
fn main() {
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
let problems: Vec<Box<problems::ProjectEulerProblem>> = vec![
box problems::Problem1,
box problems::Problem2
];
match args.flag_problem {
Some(x) => println!("Result of problem: {} is {}", x, problems[x-1].run()),
None => println!("No problem number given.")
}
}
我的问题是,有没有办法摆脱明确的problems
向量初始化,也许是通过使用宏?如上所述,实施我的应用程序的其他想法也是受欢迎的。
答案 0 :(得分:2)
您可以使用macro with repetition生成列表,而无需每次都输入完整路径和名称。
macro_rules! problem_vec(
($( $prob:tt ),*) => ({
&[
$(
&concat_idents!(Proble, $prob),
)*
]
});
);
const PROBLEMS: &'static[&'static ProjectEulerProblem] = problem_vec!(m1, m2);
注意,您不能简单地使用索引,因为concat_idents
宏需要标识符,而数字不是标识符。 concat_idents
也只在每晚提供。在稳定时,您需要提供整个结构名称:
macro_rules! problem_vec(
($( $prob:ident ),*) => ({
&[
$(
&problems::$prob,
)*
]
});
);
const PROBLEMS: &'static [&'static problems::ProjectEulerProblem] = problem_vec!(
Problem1, Problem2
);
答案 1 :(得分:0)
我的mashup
crate允许您定义一个简洁的方法来构建问题数组problems![1, 2]
。此方法适用于任何Rust版本&gt; = 1.15.0。
#[macro_use]
extern crate mashup;
mod problems {
pub trait ProjectEulerProblem {
fn run(&self);
}
pub struct Problem1;
impl ProjectEulerProblem for Problem1 {
fn run(&self) {
println!("running Project Euler problem 1");
}
}
pub struct Problem2;
impl ProjectEulerProblem for Problem2 {
fn run(&self) {
println!("running Project Euler problem 2");
}
}
}
macro_rules! problems {
($($number:tt),*) => {{
// Use mashup to define a substitution macro `m!` that replaces every
// occurrence of the tokens `"Problem" $number` in its input with the
// concatenated identifier `Problem $number`.
mashup! {
$(
m["Problem" $number] = Problem $number;
)*
}
// Invoke the substitution macro to build a slice of problems. This
// expands to:
//
// &[
// &problems::Problem1 as &problems::ProjectEulerProblem,
// &problems::Problem2 as &problems::ProjectEulerProblem,
// ]
m! {
&[
$(
&problems::"Problem" $number as &problems::ProjectEulerProblem,
)*
]
}
}}
}
fn main() {
for p in problems![1, 2] {
p.run();
}
}