Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 在安全防锈的情况下,有可能实现单线程零成本记忆,而不存在易变性?_Rust - Fatal编程技术网

Rust 在安全防锈的情况下,有可能实现单线程零成本记忆,而不存在易变性?

Rust 在安全防锈的情况下,有可能实现单线程零成本记忆,而不存在易变性?,rust,Rust,我感兴趣的是找到或实现一个Rust数据结构,该结构提供了一种零成本的方法,可以用任意输出类型T记忆单个计算。具体来说,我想要一个通用类型的缓存,其内部数据占用的空间不超过选项,具有以下基本API: impl<T> Cache<T> { /// Return a new Cache with no value stored in it yet. pub fn new() -> Self { // ... } /// I

我感兴趣的是找到或实现一个Rust数据结构,该结构提供了一种零成本的方法,可以用任意输出类型
T
记忆单个计算。具体来说,我想要一个通用类型的
缓存
,其内部数据占用的空间不超过
选项
,具有以下基本API:

impl<T> Cache<T> {
    /// Return a new Cache with no value stored in it yet.
    pub fn new() -> Self {
        // ...
    }

    /// If the cache has a value stored in it, return a reference to the 
    /// stored value. Otherwise, compute `f()`, store its output
    /// in the cache, and then return a reference to the stored value.
    pub fn call<F: FnOnce() -> T>(&self, f: F) -> &T {
        // ...
    }
}
是否可以在safe Rust中实现这种类型(即,不编写我们自己的
unsafe
代码,仅间接依赖标准库中的
unsafe
代码)

显然,
call
方法需要变异
self
,这意味着
Cache
必须使用某种形式的内部可变性。但是,似乎不可能使用
单元格
,因为
单元格
无法按照上面
调用
的所需API的要求检索对封闭值的引用。这是一个很好的理由,
Cell
提供这样的引用是不合理的,因为它无法确保引用值在引用的生命周期内不会发生变化。另一方面,对于
缓存
类型,在调用一次
调用
后,上面的API不提供任何方式让存储值再次变异,因此它可以安全地发出一个与
缓存
本身的生命周期一样长的引用

如果
Cell
无法工作,我很好奇Rust标准库是否会为内部可变性提供一些其他安全的构建块,这些构建块可用于实现此
缓存

无论是
RefCell
还是
Mutex
都不能实现以下目标:

  • 它们不是零成本:它们需要存储比
    选项
    更多的数据,并添加不必要的运行时检查
  • 它们似乎没有提供任何方法来返回具有我们想要的生存期的真实引用——相反,我们只能返回一个
    Ref
    MutexGuard
    ,这不是一回事

  • 仅使用
    选项
    不会提供相同的功能:如果我们共享对
    缓存
    的不可变引用,则此类引用的任何持有者都可以调用
    调用
    并获得所需的值(并在过程中对
    缓存
    进行变异,以便将来的调用将检索相同的值);然而,共享对
    选项
    的不可变引用时,不可能对
    选项
    进行变异,因此无法工作

    怎么办?请您在问题中编辑一下,您不是在寻找
    Sync
    解决方案吗?这也是我的第一个问题,而且可能是唯一可能解决你任务的办法。@BrentKerby:哦,我相信它能;但你需要某种“同步选项”。实际上,这引发了另一个问题:
    f
    被多次调用是否重要?值得注意的是,如果对
    f()
    的调用以某种方式调用了
    Cache::call
    ,从而触发另一次执行
    f()
    ?是的,我现在确信我最初的实现是不可靠的,因为它可能导致未定义的行为,由
    call
    返回的不可变引用引用的值仍然可能发生from变异。我现在对它进行了修改,以防止
    f()
    本身可能在同一
    缓存上调用
    call
    。这东西肯定很难弄对!为了它的价值:
    use std::cell::UnsafeCell;
    
    pub struct Cache<T> {
        value: UnsafeCell<Option<T>>
    }
    
    impl<T> Cache<T> {
        pub fn new() -> Self {
            Cache { value: UnsafeCell::new(None) }
        }
    
        pub fn call<F: FnOnce() -> T>(&self, f: F) -> &T {
            let ptr = self.value.get();
            unsafe {
                if (*ptr).is_none() {
                    let t = f();
                    // Since `f` potentially could have invoked `call` on this
                    // same cache, to be safe we must check again that *ptr
                    // is still None, before setting the value.
                    if (*ptr).is_none() {
                        *ptr = Some(t);
                    }
                }
                (*ptr).as_ref().unwrap()
            }
        }
    }