在 Rust 中拥有线程安全的延迟初始化的可能可变值的正确方法是什么?

What's the right way to have a thread-safe lazy-initialized possibly mutable value in Rust?

我有一个结构,其中包含一个初始化起来相当昂贵的字段,所以我希望能够懒惰地这样做。但是,这在采用 &self 的方法中可能是必需的。该字段还需要能够在初始化后进行修改,但这只会发生在采用 &mut self 的方法中。

在 Rust 中正确的(如惯用的,以及线程安全的)方法是什么?在我看来,这两个约束中的任何一个都是微不足道的:

但是,我不太确定如何处理这两个位置。 RwLock 似乎是相关的,但鉴于我对 lazy-init 的源代码的了解,线程安全的惰性初始化似乎存在相当大的技巧,因此我对基于它推出自己的解决方案犹豫不决.

最简单的解决方案是RwLock<Option<T>>

However, I'm not quite sure what to do with both in place. RwLock seems relevant, but it appears that there is considerable trickiness to thread-safe lazy initialization given what I've seen of lazy-init's source, so I am hesitant to roll my own solution based on it.

lazy-init 使用棘手的代码,因为它保证 lock-free 创建后的访问。 Lock-free 总是有点棘手。

请注意,在 Rust 中很容易判断某事是否棘手:棘手意味着使用 unsafe 块。由于您可以在没有任何不安全块的情况下使用 RwLock<Option<T>>,因此您无需担心。


如果您想捕获一个用于初始化的闭包一次,而不是必须在每次可能的初始化时传递它[=40],则可能需要 RwLock<Option<T>> 的变体=].

在这种情况下,您需要类似 RwLock<SimpleLazy<T>> 的内容,其中:

enum SimpleLazy<T> {
    Initialized(T),
    Uninitialized(Box<FnOnce() -> T>),
}

您不必担心制作 SimpleLazy<T> Sync,因为 RwLock 会为您处理。