Как вызвать функцию, которая требует статического времени жизни с переменной, созданной в main? - PullRequest
0 голосов
/ 07 июня 2018

У меня есть определенная структура, в которой есть функция, определяющая статическое время жизни:

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

Я использую ее из main следующим образом:

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

Она предназначенадля вызова doSomething для блокировки и выполнения в течение всего времени жизни приложения.

У меня возникают проблемы с проверками времени жизни, когда утверждается, что он может пережить функцию main, что кажется странным длякак только main завершено, приложение должно завершиться.

Есть ли способ достичь этого?

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Наивный способ сделать это - с помощью переменной static, но он потребует небезопасного кода, если вам нужно установить значение внутри вашей функции main:

static mut OBJ: MyStruct = MyStruct;

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

Это также unsafe сделать что-нибудь с изменяемой статикой в ​​дальнейшем.

Гораздо лучший способ сделать это - позволить библиотеке (lazy_static) позаботиться о небезопасном коде.

#[macro_use]
extern crate lazy_static;

fn main() {
    lazy_static!{
        static ref OBJ: MyStruct = MyStruct {};
    }
    OBJ.doSomething();
}
0 голосов
/ 07 июня 2018

Основной способ для создания ссылки со временем жизни '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 специально для целей жизни.


гипер требует статической среды выполнения при запускесервер и обрабатывает каждый запрос.

Нет, это не так.Он имеет предел : '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());
}

Вы даже можете использовать внутреннюю изменчивость , если вам нужна динамическая реконфигурация.

См. Также:

...