如何在 structopt 中使用枚举?
How can I use enums in structopt?
我想让 StructOpt
使用枚举,这样每次用户通过 -d sunday
它都会被解析为 Day::Sunday
:
#[macro_use]
extern crate structopt;
use std::path::PathBuf;
use structopt::StructOpt;
// My enum
enum Day {
Sunday, Monday
}
#[derive(Debug, StructOpt)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
/// Set speed
#[structopt(short = "s", long = "speed", default_value = "42")]
speed: f64,
/// Input file
#[structopt(parse(from_os_str))]
input: PathBuf,
/// Day of the week
#[structopt(short = "d", long = "day", default_value = Day::Monday)]
day: Day,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
我目前的最佳解决方案是使用Option<String>
作为类型并传递自定义parse_day()
:
fn parse_day(day: &str) -> Result<Day, ParseError> {
match day {
"sunday" => Ok(Day::Sunday),
_ => Ok(Day::Monday)
}
Err("Could not parse a day")
}
Struct-opt 接受任何实现了 FromStr
的类型,它离你的 parse_day
函数不远:
use std::str::FromStr;
// any error type implementing Display is acceptable.
type ParseError = &'static str;
impl FromStr for Day {
type Err = ParseError;
fn from_str(day: &str) -> Result<Self, Self::Err> {
match day {
"sunday" => Ok(Day::Sunday),
"monday" => Ok(Day::Monday),
_ => Err("Could not parse a day"),
}
}
}
此外,default_value
应该是一个字符串,它将使用 from_str
.
解释为 Day
#[structopt(short = "d", long = "day", default_value = "monday")]
day: Day,
错误信息是:
error[E0277]: the trait bound `Day: std::str::FromStr` is not satisfied
--> src/main.rs:22:17
|
22 | #[derive(Debug, StructOpt)]
| ^^^^^^^^^ the trait `std::str::FromStr` is not implemented for `Day`
|
= note: required by `std::str::FromStr::from_str`
您可以通过为 Day
实现 FromStr
(参见 )来解决该问题,正如消息所暗示的那样,或者通过为 Day
定义解析函数:
fn parse_day(src: &str) -> Result<Day, String> {
match src {
"sunday" => Ok(Day::Sunday),
"monday" => Ok(Day::Monday),
_ => Err(format!("Invalid day: {}", src))
}
}
并使用 try_from_str
属性指定它:
/// Day of the week
#[structopt(short = "d", long = "day", parse(try_from_str = "parse_day"), default_value = "monday")]
day: Day,
works, but the arg_enum!
macro is a more concise way of doing it, as demonstrated in this example from structopt
:
arg_enum! {
#[derive(Debug)]
enum Day {
Sunday,
Monday
}
}
#[derive(StructOpt, Debug)]
struct Opt {
/// Important argument.
#[structopt(possible_values = &Day::variants(), case_insensitive = true)]
i: Day,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
这会让您将工作日解析为 Sunday
或 sunday
。
显然 arg_enum!
已被弃用,clap 3
即将推出,see the doc here。我只是重构为直接使用clap而不是StructOpts
,看来它们已经合并了。
在您的 Cargo.toml
中,您不再需要 StructOpt:
clap = { version = "3.1.17", features = ["derive"] }
在你的 main.rs
中,你现在将使用 clap
和内置的 struct opt,注意字段上的文档变成了整洁的字段帮助消息值:
use clap::StructOpt;
#[derive(clap::ArgEnum, Debug, Clone)]
enum PossibleWords {
Hello,
World,
}
#[derive(Debug, clap::Parser, Clone)]
#[clap(long_about = "The worst Hello World!!! App in the world!")]
pub struct Args {
/// You can't have everything in life, which word should we print?
#[clap(arg_enum, long, default_value_t = YourEnum::Hello)]
word: PossibleWords,
//// Exclamation marks are included FOR FREE with the word of your choice.
#[clap(long, default_value_t = 10)]
number_of_exclamation_marks: u64,
}
pub fn main() {
let args = Args::parse();
}
我想让 StructOpt
使用枚举,这样每次用户通过 -d sunday
它都会被解析为 Day::Sunday
:
#[macro_use]
extern crate structopt;
use std::path::PathBuf;
use structopt::StructOpt;
// My enum
enum Day {
Sunday, Monday
}
#[derive(Debug, StructOpt)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
/// Set speed
#[structopt(short = "s", long = "speed", default_value = "42")]
speed: f64,
/// Input file
#[structopt(parse(from_os_str))]
input: PathBuf,
/// Day of the week
#[structopt(short = "d", long = "day", default_value = Day::Monday)]
day: Day,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
我目前的最佳解决方案是使用Option<String>
作为类型并传递自定义parse_day()
:
fn parse_day(day: &str) -> Result<Day, ParseError> {
match day {
"sunday" => Ok(Day::Sunday),
_ => Ok(Day::Monday)
}
Err("Could not parse a day")
}
Struct-opt 接受任何实现了 FromStr
的类型,它离你的 parse_day
函数不远:
use std::str::FromStr;
// any error type implementing Display is acceptable.
type ParseError = &'static str;
impl FromStr for Day {
type Err = ParseError;
fn from_str(day: &str) -> Result<Self, Self::Err> {
match day {
"sunday" => Ok(Day::Sunday),
"monday" => Ok(Day::Monday),
_ => Err("Could not parse a day"),
}
}
}
此外,default_value
应该是一个字符串,它将使用 from_str
.
Day
#[structopt(short = "d", long = "day", default_value = "monday")]
day: Day,
错误信息是:
error[E0277]: the trait bound `Day: std::str::FromStr` is not satisfied
--> src/main.rs:22:17
|
22 | #[derive(Debug, StructOpt)]
| ^^^^^^^^^ the trait `std::str::FromStr` is not implemented for `Day`
|
= note: required by `std::str::FromStr::from_str`
您可以通过为 Day
实现 FromStr
(参见 Day
定义解析函数:
fn parse_day(src: &str) -> Result<Day, String> {
match src {
"sunday" => Ok(Day::Sunday),
"monday" => Ok(Day::Monday),
_ => Err(format!("Invalid day: {}", src))
}
}
并使用 try_from_str
属性指定它:
/// Day of the week
#[structopt(short = "d", long = "day", parse(try_from_str = "parse_day"), default_value = "monday")]
day: Day,
arg_enum!
macro is a more concise way of doing it, as demonstrated in this example from structopt
:
arg_enum! {
#[derive(Debug)]
enum Day {
Sunday,
Monday
}
}
#[derive(StructOpt, Debug)]
struct Opt {
/// Important argument.
#[structopt(possible_values = &Day::variants(), case_insensitive = true)]
i: Day,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
这会让您将工作日解析为 Sunday
或 sunday
。
显然 arg_enum!
已被弃用,clap 3
即将推出,see the doc here。我只是重构为直接使用clap而不是StructOpts
,看来它们已经合并了。
在您的 Cargo.toml
中,您不再需要 StructOpt:
clap = { version = "3.1.17", features = ["derive"] }
在你的 main.rs
中,你现在将使用 clap
和内置的 struct opt,注意字段上的文档变成了整洁的字段帮助消息值:
use clap::StructOpt;
#[derive(clap::ArgEnum, Debug, Clone)]
enum PossibleWords {
Hello,
World,
}
#[derive(Debug, clap::Parser, Clone)]
#[clap(long_about = "The worst Hello World!!! App in the world!")]
pub struct Args {
/// You can't have everything in life, which word should we print?
#[clap(arg_enum, long, default_value_t = YourEnum::Hello)]
word: PossibleWords,
//// Exclamation marks are included FOR FREE with the word of your choice.
#[clap(long, default_value_t = 10)]
number_of_exclamation_marks: u64,
}
pub fn main() {
let args = Args::parse();
}