如果一个变量在 Rust 中 main 函数的末尾被删除,为什么它不会被借用用于静态?

Why is a variable not borrowed for static if it is dropped at the end of the main function in Rust?

提问人:Plegeus 提问时间:6/26/2023 最后编辑:Plegeus 更新时间:6/26/2023 访问量:87

问:

我正在尝试传递一个捕获局部变量的闭包:

fn main() {

  /* snip */

  let COINT = some_function_call();

  /* snip */

  hermes.with_task(
    u32::MAX,
    1,
    1,
    Box::new(
      |hermes| {
        let mut rng = rand::thread_rng();
        Command::SpawnCommand(
          COIN, 
          Vec3::new(
            rng.gen_range(-WORLD_SIZE..WORLD_SIZE),
            5.5,
            rng.gen_range(-WORLD_SIZE..WORLD_SIZE)
          )
        )
      }
    )
  );

  /* snip */

}

它是变量 COIN。

The error I receive is as follows: 
error[E0597]: `COIN` does not live long enough
   --> src\main.rs:250:11
    |
246 | /     Box::new(
247 | |       |hermes| {
    | |       -------- value captured here
248 | |         let mut rng = rand::thread_rng();
249 | |         Command::SpawnCommand(
250 | |           COIN,
    | |           ^^^^ borrowed value does not live long enough
...   |
257 | |       }
258 | |     )
    | |_____- cast requires that `COIN` is borrowed for `'static`
...
272 |   }
    |   - `COIN` dropped here while still borrowed

方法with_task定义如下:

impl Hermes {

  /* snip */
  
  pub fn with_task<'a: 'static>(&mut self, repeat: u32, span: u32, offset: u32, f: Box<dyn Fn(&Hermes) -> Command + 'a>) -> usize {

    let t = TaskInfo {
      task: f,
      repeat,
      span,
      counter: offset,
    };

    self.tasks.push(t);

    self.tasks.len() - 1
  }

  /* snip */

}

最让我困惑的是错误中的这一行:

272 |   }
    |   - `COIN` dropped here while still borrowed

这正是主要功能结束的地方,我只是不明白问题出在哪里。

谢谢你帮助我:)

编辑下面是一个可重现的示例:

struct Foo {
    tasks: Vec<Box<dyn Fn(&Foo) -> Command>>,
}
impl Foo {
    fn with_task(&mut self, f: Box<dyn Fn(&Foo) -> Command>) {
        self.tasks.push(f);
    }
}

enum Command {
    Com1(usize),
}


fn main() {

    let VAR: usize = 0;
    let mut foo = Foo {
        tasks: Vec::new(),
    };

    foo.with_task(Box::new(
        |foo| {
            Command::Com1(VAR)
        }
    ));

}
Rust Closures Lifetime 借用检查器 范围

评论

3赞 Ivan C 6/26/2023
例如,生成的线程可能比 .main
1赞 isaactfa 6/26/2023
@IvanC这是真的吗?文档说,“除非生成线程是主线程,否则生成线程可能会也可能不会比生成线程长寿”,这有点模棱两可,但我推断意思是“除非它是主线程,否则可能会长于生成线程”。不过,这个问题并不重要。除非项目被声明或属于极少数异常,否则无论它是否在 main 的开头或结尾被丢弃,它都不会是静态的。static
3赞 Finomnis 6/26/2023
不如代替?我的直觉说,问题在于你没有进入任务,所以它仍然是一个参考,你不能从线程中引用。(除非你使用 ,但这不是给定库 API 的一部分)Box::new(move |hermes| {Box::new(|hermes| {COINTstd::thread::scope
1赞 rodrigo 6/26/2023
“我只想通过一个捕获其环境的闭包......”您可以通过将环境 -ing 到闭包中来捕获环境,或者如果要通过引用捕获环境,则必须向类型添加生存期参数:playground。当然,或者你用来共享环境。moveFooRc
2赞 Sven Marnach 6/26/2023
最小示例中的实际问题是隐式表示 Box<dyn(&Foo) -> Command + 'static>。在引入显式生存期绑定后,代码工作正常,即使没有 .Box<dyn Fn(&Foo) -> Command>move

答: 暂无答案