Structopt with computed default value

Hi,

I'm trying to have Structopt accept a path option with a computed default value:

use structopt::StructOpt;
use std::{env, ffi::OsString};
use std::path::PathBuf;

#[derive(Debug,StructOpt)]
pub struct Args {
  /// Directory holding kubectl configuration
  #[structopt(long,parse(from_os_str),default_value=format!("{}/.kube",env::var("HOME").unwrap_or(String::from("."))).as_str())]
  pub kubeconfig: PathBuf,
}

But the compiler's not happy with returning a temporary value

7  | #[derive(Debug,StructOpt)]
   |                ^^^^^^^^^ returns a value referencing data owned by the current function
...
22 |   #[structopt(long,parse(from_os_str),default_value=format!("{}/.kube",env::var("HOME").unwrap_or(String::from("."))).as_str())]
   |                                                     ----------------------------------------------------------------- temporary value created here

Is there a way to do that?

Thanks,
Chris

I never used structopt (or clap) myself before, so no idea if there’s a better way, but you could perhaps do something like this

use once_cell::sync::Lazy;
use std::path::PathBuf;
use std::{env, ffi::OsString};
use structopt::StructOpt;

static DEFAULT_KUBECONFIG: Lazy<String> =
    Lazy::new(|| format!("{}/.kube", env::var("HOME").as_deref().unwrap_or(".")));

#[derive(Debug, StructOpt)]
pub struct Args {
    /// Directory holding kubectl configuration
    #[structopt(long,parse(from_os_str),default_value=&DEFAULT_KUBECONFIG)]
    pub kubeconfig: PathBuf,
}

Edit: Judging by some cargo expand output, structopt uses lazy_static internally for a default value when you’re using default_value without an argument. (The docs say this only works for types that implement Default and ToString. Using lazy_static or once_cell::sync::Lazy is pretty similar, so it seems like there probably really is (at least as far as runtime-behavior is concerned) no better way than what I suggested above.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.