Reputation: 26965
To reduce lines of code I moved my clap App
to another file with something like this:
use clap::{App, AppSettings, Arg, ArgMatches}; // 2.33.3
use std::path::Path;
fn main() {
let s3m_dir = Path::new("/tmp").join(".s3m");
let matches = get_matches(s3m_dir.display().to_string());
println!("{:#?}", matches);
}
pub fn get_matches(home_dir: String) -> ArgMatches<'static> {
App::new("s3m")
.version(env!("CARGO_PKG_VERSION"))
.setting(AppSettings::SubcommandsNegateReqs)
.after_help(format!("foo bar: {}", home_dir).as_ref())
.arg(
Arg::with_name("config")
.help("config.yml")
.long("config")
.short("c")
.default_value(&format!("{}/.s3m/config.yml", home_dir))
.required(true)
.value_name("config.yml"),
)
.get_matches()
}
The problem I have is that I don't know how could I use the argument home_dir
as the default_value
, here:
.default_value(&format!("{}/.s3m/config.yml", home_dir))
The signature for default_value is:
pub fn default_value(self, val: &'a str) -> Self
How could I pass a format!("{}/.s3m/config.yml", home_dir
with a lifetime in other to satisfy the signature?
Upvotes: 2
Views: 1363
Reputation: 43852
I haven't used clap
, so there may be a better approach, but the general Rust solution to this problem is to have some data structure that owns the needed strings, so that the ArgMatches
can have a lifetime dependent on it:
struct ArgParser {
home_dir: PathBuf,
default_config: OsString,
}
impl ArgParser {
pub fn new(home_dir: &Path) -> Self {
let default_config_path: PathBuf = home_dir.join(".s3m/config.yml");
Self {
home_dir: home_dir.to_owned(),
default_config: default_config_path.as_os_str().to_owned(),
}
}
I've also adjusted the config path to use Path::join
rather than string formatting and OsString
instead of String
, which aren't actually relevant to your question but should be more correct.
Now we can modify get_matches
to work with this, as part of impl ArgParser
:
pub fn get_matches(&self) -> ArgMatches {
App::new("s3m")
.version(env!("CARGO_PKG_VERSION"))
.setting(AppSettings::SubcommandsNegateReqs)
.after_help(format!("foo bar: {}", self.home_dir.display()).as_ref())
.arg(
Arg::with_name("config")
.help("config.yml")
.long("config")
.short("c")
.default_value_os(&self.default_config)
.required(true)
.value_name("config.yml"),
)
.get_matches()
}
}
Notice that there is no lifetime parameter given for ArgMatches
. This is because the compiler will automatically infer the lifetime for us, as if we had written:
pub fn get_matches<'a>(&'a self) -> ArgMatches<'a> {...}
The lifetime is no longer 'static
, but it can't be 'static
(unless you choose to leak the strings that you're configuring App
with). Instead, if you you need a string to live longer than the ArgParser
, use .to_owned()
to convert &'a str
into a String
that can live independently.
Upvotes: 5