正确解析 Clap ArgMatches 的惯用生锈方法
Idiomatic rust way to properly parse Clap ArgMatches
我正在学习 Rust 并尝试找到类似实用程序的工具(是的,另一个),我正在使用 clap 并尝试支持程序参数的命令行和配置文件(这与 clap yml 无关)文件)。
我正在尝试解析命令,如果没有命令传递给应用程序,我将尝试从配置文件加载它们。
现在我不知道如何以惯用的方式做到这一点。
fn main() {
let matches = App::new("findx")
.version(crate_version!())
.author(crate_authors!())
.about("find + directory operations utility")
.arg(
Arg::with_name("paths")
...
)
.arg(
Arg::with_name("patterns")
...
)
.arg(
Arg::with_name("operation")
...
)
.get_matches();
let paths;
let patterns;
let operation;
if matches.is_present("patterns") && matches.is_present("operation") {
patterns = matches.values_of("patterns").unwrap().collect();
paths = matches.values_of("paths").unwrap_or(clap::Values<&str>{"./"}).collect(); // this doesn't work
operation = match matches.value_of("operation").unwrap() { // I dont like this
"Append" => Operation::Append,
"Prepend" => Operation::Prepend,
"Rename" => Operation::Rename,
_ => {
print!("Operation unsupported");
process::exit(1);
}
};
}else if Path::new("findx.yml").is_file(){
//TODO: try load from config file
}else{
eprintln!("Command line parameters or findx.yml file must be provided");
process::exit(1);
}
if let Err(e) = findx::run(Config {
paths: paths,
patterns: patterns,
operation: operation,
}) {
eprintln!("Application error: {}", e);
process::exit(1);
}
}
有一种惯用的方法可以将 Option
和 Result
类型的值提取到同一范围,我的意思是我读过的所有示例都使用 match
或 if let Some(x)
在模式匹配范围内使用 x
值,但我需要将该值分配给变量。
有人可以帮我解决这个问题,或者给我指出正确的方向吗?
此致
就我个人而言,我认为使用 match 语句并将其折叠或将其放在另一个函数中没有任何问题。但是如果你想删除它,有很多选择。
可以使用 .default_value_if()
方法,即 impl
用于 clap::Arg
,并且根据匹配的匹配臂具有不同的默认值。
//sets value of arg "other" to "default" if value of "--opt" is "special"
let m = App::new("prog")
.arg(Arg::with_name("opt")
.takes_value(true)
.long("opt"))
.arg(Arg::with_name("other")
.long("other")
.default_value_if("opt", Some("special"), "default"))
.get_matches_from(vec![
"prog", "--opt", "special"
]);
assert_eq!(m.value_of("other"), Some("default"));
此外,您可以向 operation
添加一个验证器,或者将您的有效操作值转换为标志。
这是一个将匹配臂值转换为单独标志的示例(为清楚起见,使用较小的示例)。
extern crate clap;
use clap::{Arg,App};
fn command_line_interface<'a>() -> clap::ArgMatches<'a> {
//Sets the command line interface of the program.
App::new("something")
.version("0.1")
.arg(Arg::with_name("rename")
.help("renames something")
.short("r")
.long("rename"))
.arg(Arg::with_name("prepend")
.help("prepends something")
.short("p")
.long("prepend"))
.arg(Arg::with_name("append")
.help("appends something")
.short("a")
.long("append"))
.get_matches()
}
#[derive(Debug)]
enum Operation {
Rename,
Append,
Prepend,
}
fn main() {
let matches = command_line_interface();
let operation = if matches.is_present("rename") {
Operation::Rename
} else if matches.is_present("prepend"){
Operation::Prepend
} else {
//DEFAULT
Operation::Append
};
println!("Value of operation is {:?}",operation);
}
希望对您有所帮助!
编辑:
您还可以将 Subcommands 用于您的特定操作。这完全取决于您想要的界面。
let app_m = App::new("git")
.subcommand(SubCommand::with_name("clone"))
.subcommand(SubCommand::with_name("push"))
.subcommand(SubCommand::with_name("commit"))
.get_matches();
match app_m.subcommand() {
("clone", Some(sub_m)) => {}, // clone was used
("push", Some(sub_m)) => {}, // push was used
("commit", Some(sub_m)) => {}, // commit was used
_ => {}, // Either no subcommand or one not tested for...
}
我正在学习 Rust 并尝试找到类似实用程序的工具(是的,另一个),我正在使用 clap 并尝试支持程序参数的命令行和配置文件(这与 clap yml 无关)文件)。
我正在尝试解析命令,如果没有命令传递给应用程序,我将尝试从配置文件加载它们。 现在我不知道如何以惯用的方式做到这一点。
fn main() {
let matches = App::new("findx")
.version(crate_version!())
.author(crate_authors!())
.about("find + directory operations utility")
.arg(
Arg::with_name("paths")
...
)
.arg(
Arg::with_name("patterns")
...
)
.arg(
Arg::with_name("operation")
...
)
.get_matches();
let paths;
let patterns;
let operation;
if matches.is_present("patterns") && matches.is_present("operation") {
patterns = matches.values_of("patterns").unwrap().collect();
paths = matches.values_of("paths").unwrap_or(clap::Values<&str>{"./"}).collect(); // this doesn't work
operation = match matches.value_of("operation").unwrap() { // I dont like this
"Append" => Operation::Append,
"Prepend" => Operation::Prepend,
"Rename" => Operation::Rename,
_ => {
print!("Operation unsupported");
process::exit(1);
}
};
}else if Path::new("findx.yml").is_file(){
//TODO: try load from config file
}else{
eprintln!("Command line parameters or findx.yml file must be provided");
process::exit(1);
}
if let Err(e) = findx::run(Config {
paths: paths,
patterns: patterns,
operation: operation,
}) {
eprintln!("Application error: {}", e);
process::exit(1);
}
}
有一种惯用的方法可以将 Option
和 Result
类型的值提取到同一范围,我的意思是我读过的所有示例都使用 match
或 if let Some(x)
在模式匹配范围内使用 x
值,但我需要将该值分配给变量。
有人可以帮我解决这个问题,或者给我指出正确的方向吗?
此致
就我个人而言,我认为使用 match 语句并将其折叠或将其放在另一个函数中没有任何问题。但是如果你想删除它,有很多选择。
可以使用 .default_value_if()
方法,即 impl
用于 clap::Arg
,并且根据匹配的匹配臂具有不同的默认值。
//sets value of arg "other" to "default" if value of "--opt" is "special"
let m = App::new("prog")
.arg(Arg::with_name("opt")
.takes_value(true)
.long("opt"))
.arg(Arg::with_name("other")
.long("other")
.default_value_if("opt", Some("special"), "default"))
.get_matches_from(vec![
"prog", "--opt", "special"
]);
assert_eq!(m.value_of("other"), Some("default"));
此外,您可以向 operation
添加一个验证器,或者将您的有效操作值转换为标志。
这是一个将匹配臂值转换为单独标志的示例(为清楚起见,使用较小的示例)。
extern crate clap;
use clap::{Arg,App};
fn command_line_interface<'a>() -> clap::ArgMatches<'a> {
//Sets the command line interface of the program.
App::new("something")
.version("0.1")
.arg(Arg::with_name("rename")
.help("renames something")
.short("r")
.long("rename"))
.arg(Arg::with_name("prepend")
.help("prepends something")
.short("p")
.long("prepend"))
.arg(Arg::with_name("append")
.help("appends something")
.short("a")
.long("append"))
.get_matches()
}
#[derive(Debug)]
enum Operation {
Rename,
Append,
Prepend,
}
fn main() {
let matches = command_line_interface();
let operation = if matches.is_present("rename") {
Operation::Rename
} else if matches.is_present("prepend"){
Operation::Prepend
} else {
//DEFAULT
Operation::Append
};
println!("Value of operation is {:?}",operation);
}
希望对您有所帮助!
编辑:
您还可以将 Subcommands 用于您的特定操作。这完全取决于您想要的界面。
let app_m = App::new("git")
.subcommand(SubCommand::with_name("clone"))
.subcommand(SubCommand::with_name("push"))
.subcommand(SubCommand::with_name("commit"))
.get_matches();
match app_m.subcommand() {
("clone", Some(sub_m)) => {}, // clone was used
("push", Some(sub_m)) => {}, // push was used
("commit", Some(sub_m)) => {}, // commit was used
_ => {}, // Either no subcommand or one not tested for...
}