Reputation: 1
I'm parsing arguments with clap
however I'm slightly confused about how I should structure my program after those arguments are parsed:
What I'm finding is that I need an argument from the command line -- the --verbose
flag for instance -- and so I pull that out and now have a boolean that models this, then I end up passing that boolean to all of my functions. It never changes.
Then I'll introduce a new argument on the command line, again I'll want multiple functions to have access to these variables too. So now I convert the clap .get_matches()
to a struct that represents the config, and I end up passing that struct to all my functions. It never changes.
I get that we don't want global mutable state. But is there a common idiom for dealing with global state that is only mutated until after the argument parsing? Moreover, is there any guidance on how to handle something like a verbose
flag? Do I need to explicitly pass that to every function?
I don't think the above linked questions answers this because I'm not sure I need global mutable state. The comment,
there are indeed disadvise by default, but not when used for a good use case like option program, it's clearly OK tier. – Stargateur 15 mins ago
Is more to the question. What defines "OK tier"? Is it "OK Tier" for example if main occurs in a Tokio binary? What are the safety concerns with doing this? Is there some other method the compiler affords to mutate a variable for the purposes of storing boot state and making it available globally?
Upvotes: 1
Views: 807
Reputation: 33
If you parse the arguments and never mutate the variable again and you don't want to share it across threads, you can get rid of all the complicated stuff and just use a reference counted public static.
// this goes where the Cli struct is, args.rs for example
thread_local! {
pub static ARGS: Rc<Cli> = Rc::new(Cli::parse());
}
Where Cli is the argument struct from the clap derive parser. For example:
#[derive(Parser)]
pub struct Cli {
/// Verbose mode
#[arg(long, short = 'v')]
pub verbose: bool,
}
In a function that wants to use ARGS, you need to get it out of the Rc first. But cloning an Rc is incredibly cheap, it just increments an integer.
use crate::args::ARGS;
pub fn myfunction(&self) -> String {
let args = ARGS.with(|a| a.clone());
// then use args
if args.verbose {
println!("This is verbose!");
} else {
println!("This is not verbose!");
}
}
I think this is the base model. If you need to share this among threads, remove thread local and add OnceCell. If you need to mutate later on, use Mutex. But usage will be more complicated with that.
Upvotes: 0