Rust 'borrowed value does not live long enough' 在分配给静态变量时

Rust 'borrowed value does not live long enough' while assigning to a static variable

我的目标是保留一个静态变量并让该值被 CLI 参数覆盖,但我很难找到一种方法来保留我从 args 迭代器获得的值的静态副本。

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.")
        }
      }
    }
  }
}

给出如下编译错误

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();
   | 

我有什么方法可以从迭代器创建值的静态副本吗?

你不能那样做。静态变量必须是 'static,即不能包含非 'static 的生命周期。这就是为什么您可以在静态引用的声明中省略生命周期。你的实际上相当于:

static mut ROOT_DIRECTORY: &'static str = "C:\test\source";

而您的 args 是局部变量,因此对它的引用不是 'static

Is there any way for me to create a static copy of the value from the iterator?

最简单的选择是让静态变量拥有它的数据,而不是引用,也就是说,让它成为一个String。不幸的是,静态构造函数必须是 const,而我所知道的 String 的唯一 const 构造函数是 String::new()。您可以添加一个辅助函数 fn get_root_directory() -> &'static str 来读取全局变量和 returns 默认值(如果未设置),但如果您喜欢它,您可以将静态设置为 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")
    }
}

另一种选择是泄漏堆分配的字符串以使其成为静态的。只要你只分配给它一次,泄漏应该不是问题。类似于:

static mut ROOT_DIRECTORY: &'static str = "default value";

fn main() {
    let x = "...".to_string();
    unsafe {
        ROOT_DIRECTORY = Box::leak(x.into_boxed_str());
    }
}