在Rust中运行时用环境变量填充static/const

6mw9ycah  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(132)

我正在尝试在服务启动时从系统环境中加载密码和敏感数据。我已经尝试了许多不同的方法,但似乎找不到在Rust中做到这一点的正确方法。

const PASSWORD: String = var("PASSWORD").unwrap();

不工作,因为method calls in constants are limited to constant inherent methods。同样的情况也适用于static(显然,错误是静态的)。
另一种方法是

const PASSWORD: &'static str = env!("PASSWORD");

但问题是,它将在编译时定义为env!是一个宏(至少这是我的理解)。
我还考虑过简单地将对var("...").unwrap()的调用 Package 在一个函数中,但该解决方案并不适合我,并且还允许在整个运行时更改值,并且在服务启动时不验证它们。
正如你所看到的,我对Rust是个新手。我真的很感激你的回答,如果你不能只是解释如何在运行时加载const/static,但也解释为什么我做的是愚蠢和错误的:)

7eumitmz

7eumitmz1#

conststatic在Rust中扮演不同的角色。
const不仅意味着一个常数,它还意味着一个 * 编译时 * 常数,一个在编译时确定的值,并记录在程序的只读存储器中。它不适合你的情况。
static表示一个全局变量,其生存期将跨越整个程序。它可能是可变的,在这种情况下,它必须是Sync以避免并发修改。static变量必须从常量初始化,以便在程序开始时可用。
那么,如何在运行时读取变量并使其可用呢?好吧,一个干净的解决方案是完全避免全局变量...
.但由于它可以方便,有一个板条箱:lazy_static!

use std::env::var;
use lazy_static::lazy_static;

lazy_static! {
    static ref PASSWORD: String = var("PASSWORD").unwrap();
}

fn main() {
    println!("{:?}", *PASSWORD);
}

在第一次访问变量时,执行表达式以加载其值,然后将值存储并可使用,直到程序结束。

ukdjmx9f

ukdjmx9f2#

所有Matthieu M. said仍然是正确的,尽管现在你应该使用OnceLock而不是lazy_static

use std::sync::OnceLock;
use std::env::var;
fn password() -> &'static str {
    static PASSWORD: OnceLock<String> = OnceLock::new();
    PASSWORD.get_or_init(|| {
        var("PASSWORD").unwrap()
    })
}

一旦它稳定或每晚运行,您可以简化为LazyLock

#![feature(lazy_cell)]
use std::sync::LazyLock;
use std::env::var;
static PASSWORD: LazyLock<String> = LazyLock::new(|| {
    var("PASSWORD").unwrap()
});

您还可以通过使用Box<str>而不是String并对字符串调用.into()来为每个变量保存一个字(根据String实际上是如何分配的,可能会保存更多字),但这可能涉及到对字符串内容的额外复制。

相关问题