Инициализация переменной Rust, переданной в асин c код, такой как tokio и hyper - PullRequest
1 голос
/ 12 февраля 2020

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

Как создать безопасное, идиоматически и без лишних потерь производительности такое значение?

  • Если я создам его в main и передам его hyper, он не проживет достаточно долго.
  • Если я создам его с lazy_static!, он вычисляется только при первом обращении к нему. Если он не может быть вычислен, то я не хочу запускать и остальную часть приложения. Я предпочел бы знать, что не могу подключиться к базе данных при запуске приложения, а не когда клиент делает запрос.
  • Если я сделаю это static mut, то я не смогу использовать его в код безопасности.

В идеале я хотел бы сделать что-то вроде:

#[tokio::main]
pub async fn main() {
    let db = init_db();

    // This uses a hyper server, passes db around
    // to tokio and hyper handlers, etc.
    run_app(&db);
}

Ответы [ 3 ]

3 голосов
/ 12 февраля 2020

Вы можете утечь память, чтобы у ссылки было время жизни 'static:

#[tokio::main]
pub async fn main() {
    let db = Box::leak(Box::new(init_db())) as &'static _;

    // This uses a hyper server, passes db around
    // to tokio and hyper handlers, etc.
    run_app(db);
}
3 голосов
/ 12 февраля 2020

Если я создаю его с помощью lazy_static!, он вычисляется только при первом обращении.

Существует специальная c функция для управления, когда переменная lazy stati c is initialize d:

use lazy_static::lazy_static; // 1.4.0

lazy_static! {
    static ref THING: String = String::from("a");
}

#[tokio::main]
pub async fn main() {
    lazy_static::initialize(&THING);
    run_app();
}
2 голосов
/ 12 февраля 2020

Вы можете обернуть данные в Arc, так что ваши данные могут быть переданы и они будут жить, пока на них не останется никаких ссылок:

use tokio::prelude::*;
use tokio;
use std::sync::Arc;

async fn init_db() -> Arc<String> {
    Arc::new("Foo".to_string())
}

async fn run_app(data: Arc<String>) {
    for _ in 0..10 {
        println!("{}", data);
    }
}

#[tokio::main]
pub async fn main() {
    let db = init_db().await;

    // This uses a hyper server, passes db around
    // to tokio and hyper handlers, etc.
    run_app(db).await;
}

Версия для детской площадки

...