Structopt `Option` with `Some(_)` default value

I have a CLI implemented using structopt. I would like to have an optional flag which defaults to some value that can be overridden, or switched off completely. For example

prog           # x = Some(3)
prog -x 4      # x = Some(4)
prog -x no     # x = None

This hopefully illustrates that

  • x = 3 by default
  • the default can be overridden
  • the option can be switched off

The use of no as the switch-off token, is just an example: any convenient to type marker would do.

Can you suggest a clean way of implementing this in structopt?

You can use a custom parse function for this. You'll also need to spell the field's type as something other than just Option<T>, to disable structopt's default handling of that type:

use std::num::ParseIntError;
use structopt::StructOpt;

// alias to disable structopt's type magic
type MyOption<T> = Option<T>;

#[derive(Debug, StructOpt)]
struct Opt {
    #[structopt(
        short = "x",
        default_value = "3",
        parse(try_from_str = number_or_no))]
    x: MyOption<i32>,
}

fn number_or_no(s: &str) -> Result<MyOption<i32>, ParseIntError> {
    let val = if s == "no" { None } else { Some(s.parse()?) };
    Ok(val)
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt.x);
}
3 Likes

My attempt was essentially identical to yours, except for the type alias. Without that, the errors were very confusing.

Many thanks!

1 Like