【问题标题】:How do I call a function that requires a 'static lifetime with a variable created in main?如何使用在 main 中创建的变量调用需要“静态生命周期”的函数?
【发布时间】:2018-11-17 08:00:31
【问题描述】:

我已经定义了一个结构,它有一个定义静态生命周期的函数:

impl MyStruct {
    pub fn doSomething(&'static self) {
        // Some code goes here
    }
}

我像这样从 main 消费它:

fn main() {
    let obj = MyStruct {};
    obj.doSomething();
}

它的目的是让doSomething 调用在应用程序的生命周期内阻塞和执行。

我遇到了生命周期检查的问题,它指出它可能比main 函数的寿命更长,这对我来说似乎很奇怪,因为一旦main 完成,应用程序应该退出。

有没有办法做到这一点?

【问题讨论】:

  • 你到底想做什么?
  • @Boiethios 正是我所说的,该函数调用另一个需要静态生命周期的函数,因此函数本身需要静态生命周期才能符合这些要求。我需要从 main 调用该函数,编译器会阻止该函数,因为该结构显然比 main 寿命更长。
  • 这个需要静态生命周期的函数是什么?
  • 您的问题是您需要对 self 的引用才能拥有静态的生存时间,但它是在 main 函数中定义的。试试:play.rust-lang.org/…
  • @Boiethios hyper 在运行服务器和处理每个请求时需要静态运行时。更糟糕的是它实际上是两层静态需求(两个闭包)。

标签: rust lifetime


【解决方案1】:

最简单的方法是使用static 变量,但如果您需要在main 函数中实际设置值,则需要使用不安全的代码:

static mut OBJ: MyStruct = MyStruct;

fn main() {
    unsafe {
        OBJ = MyStruct {};
        OBJ.doSomething();
    }
}

这也是 unsafe 之后用可变静态做几乎任何事情。

更好的方法是让库 (lazy_static) 处理不安全的代码。

use lazy_static::lazy_static;

fn main() {
    lazy_static!{
        static ref OBJ: MyStruct = MyStruct {};
    }
    OBJ.doSomething();
}

【讨论】:

    【解决方案2】:

    创建具有'static 生命周期的引用的主要方法是创建变量static。静态变量是可以在编译时创建的:

    struct MyStruct;
    
    impl MyStruct {
        pub fn do_something(&'static self) {}
    }
    
    static OBJ: MyStruct = MyStruct;
    
    fn main() {
        OBJ.do_something();
    }
    

    随着 Rust 不断评估故事的改进,这将更加常见,但它永远不会允许在运行时进行配置。

    一个不太常见的方法是故意泄漏内存,产生一个“永远”持续的引用。不鼓励这样做,因为泄漏内存不是一件好事:

    fn main() {
        let obj = Box::leak(Box::new(MyStruct));
        obj.do_something();
    }
    

    还有可能创建一个单例:

    一旦main 完成,应用程序应该退出。

    也许,但编译器不会将main 专门用于生命周期。


    hyper 在运行服务器和处理每个请求时需要静态运行时。

    不,它没有。它的边界为: 'static,这意味着传入的任何引用都必须是'static,但您根本不必传入裸引用。

    对于这样的模式,最常见的做法是传入 Arc 之类的东西。这允许共享底层资源。

    pub fn do_something<F, T>(f: F)
    where
        F: Fn() -> T + 'static,
        T: 'static,
    {
        // "spawn" 3 threads
        f();
        f();
        f();
    }
    
    struct MyStruct;
    
    static OBJ: MyStruct = MyStruct;
    
    fn main() {
        // OK
        do_something(|| &OBJ);
    
        // Not OK
        let another = MyStruct;
        do_something(|| &another);
    
        // OK
        use std::sync::Arc;
        let shared = Arc::new(MyStruct);
        do_something(move || shared.clone());
    }
    

    如果您想要动态重新配置,您甚至可以使用interior mutability

    另见:

    【讨论】:

    • 是的,我有一个需要引用 self 的包装类,我可以传入一个解决该特定问题的 Arc,但它仍然有各种 'static 投诉。
    • @Shepmaster 来自 rust 参考“静态项目不会在程序结束时调用 drop”,因此 static 和 Box::leak 基本相同,除了后者在堆上。老实说,考虑到 rust 对初始化静态变量有多么烦人,Box::leak 似乎是一种通过运行时初始化创建静态变量的好方法。
    • @Eloff 我不明白你评论的目的是什么。答案已经将泄漏内存列为解决方案。
    • @Shepmaster 您提到“不应该这样做,因为泄漏内存不是一件好事”,确实听起来很可怕。但这正是 rust static 的工作原理,所以我认为对于这个特定的用例不应该阻止它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2013-07-27
    • 2011-04-18
    • 2010-09-19
    相关资源
    最近更新 更多