将数据解析为模块级可变静态变量

7

我有一个模块中的一组函数需要访问一些共享的初始化状态。实际上,我想使用类似静态可变向量的方式来对其进行建模,例如:

static mut defs: Vec<String> = vec![];

fn initialize() {
    defs.push("One".to_string());
    defs.push("Two".to_string()); 
}

(示例:http://is.gd/TyNQVv,出现“不允许可变静态变量具有析构函数”错误。)
我的问题类似于Rust中是否可以使用全局变量?,但是使用了Vec(即一个具有析构函数的类型),因此那个问题的Option解决方案似乎不适用。也就是说,这与我的第一次尝试产生了相同的错误:
static mut defs: Option<Vec<String>> = None;

fn initialize() {
    let init_defs = vec![];
    init_defs.push("One".to_string());
    init_defs.push("Two".to_string()); 
    defs = Some(init_defs);
}
  1. 有没有一种方法可以访问在初始化时填充并在运行时可见的静态(“全局”)向量?

  2. 是否应该考虑其他模式来支持此用例?传递显式引用状态向量是可能的,但会使所有需要访问此状态的大量函数签名变得混乱。

1个回答

11
你可以使用lazy_static来实现这个目的:
lazy_static! {
    static ref defs: Vec<String> = {
        let mut init = vec!["One".to_string(), "Two".to_string()];
        // init.push(...); etc. etc.
        init
    }
}

在首次访问时初始化向量,之后向量将变为不可变。如果您希望稍后修改它,将其包装在std::sync::Mutex中是一个很好的第一步。

是否有其他模式应该考虑以支持这种用例?显式引用状态向量是可能的,但会使所有需要访问此状态的函数签名变得杂乱无章。

可以考虑创建一个上下文对象来存储函数所需的所有信息,例如:

struct Context {
    defs: Vec<String>
}

接着传递 Context,确保每个人都了解他们需要知道的内容。你甚至可以考虑将所有/许多/一些函数作为Context的方法,例如:

impl Context {
    fn foo(&self) {
        if self.defs.len() > 10 {
             println!("lots of defs");
        }
    }
    // ...
}

如果您需要修改上下文(自动确保线程安全),或者希望在单个进程中拥有多个独立实例,则此模式尤为适用。


1
谢谢!这个回答非常清晰地解答了我的两个问题。我特别喜欢Context结构体模式,具有impl方法的特点。感觉更符合惯用法。 - Bosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接