My goal is to keep a static variable and have the value be overridden by CLI arguments but I'm having a hard time finding a way to keep a static copy of the value I get from the args iterator.
static mut ROOT_DIRECTORY: &str = "C:\\test\\source";
fn main() {
let args: Vec<String> = env::args().collect();
let mut index = 0;
for arg in args {
match arg.as_str() {
"/r" => unsafe {
if args_length <= index + 1 {
panic!("Missing root directory value.");
}
ROOT_DIRECTORY = args.get(index + 1).unwrap();
if ROOT_DIRECTORY.is_empty() {
panic!("Root directory value cannot be empty.")
}
}
}
}
}
Gives the following compilation error
error[E0597]: `args` does not live long enough
--> src\main.rs:90:34
|
90 | ROOT_DIRECTORY = args.get(index + 1).unwrap();
| ^^^^---------------
| |
| borrowed value does not live long enough
| argument requires that `args` is borrowed for `'static`
...
168 | }
| - `args` dropped here while still borrowed
error[E0382]: borrow of moved value: `args`
--> src\main.rs:90:34
|
54 | let args: Vec<String> = env::args().collect();
| ---- move occurs because `args` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
...
76 | for arg in args {
| ----
| |
| value moved here
| help: consider borrowing to avoid moving into the for loop: `&args`
...
90 | ROOT_DIRECTORY = args.get(index + 1).unwrap();
|
Is there any way for me to create a static copy of the value from the iterator?
You cannot do that. Static variables must be 'static
, that is, must not contain non-'static
lifetimes. This is why you can elide lifetimes in the declaration of static references. Yours is actually equivalent to:
static mut ROOT_DIRECTORY: &'static str = "C:\\test\\source";
And your args
is a local variable, so a reference to it is not 'static
.
Is there any way for me to create a static copy of the value from the iterator?
The easiest option is to make the static variable own its data, instead of being a reference, that is, let it be a String
. Unfortunately, the static constructor must be const
, and the only const
constructor of String
that I know of is String::new()
. You could add a helper function fn get_root_directory() -> &'static str
that reads the global variable and returns the default if unset, but if you are into that, you could make the static a Option<String>
:
static mut ROOT_DIRECTORY: Option<String> = None;
pub fn get_root_directory() -> &'static str {
unsafe {
ROOT_DIRECTORY.as_deref().unwrap_or("C:\\test\\source")
}
}
Another option would be to leak a heap-allocated string to make it static. As long as you only assign to it once, the leak should not be a problem. Something like:
static mut ROOT_DIRECTORY: &'static str = "default value";
fn main() {
let x = "...".to_string();
unsafe {
ROOT_DIRECTORY = Box::leak(x.into_boxed_str());
}
}