【问题标题】:Implementation of Deref for container structure容器结构的 Deref 的实现
【发布时间】:2020-12-06 12:45:50
【问题描述】:

我有下一个代码,它实现了某种惰性/延迟初始化,为了方便起见,我想使用内部可变性和 Deref 实现。

pub struct Deferred<T> {
    value: RefCell<Value<T>>
}

pub enum Value<T> {
    Initialized(T),
    WaitingForValue
}

impl<T> Deferred<T> {
    pub fn init_later() -> Self {
        Self { value: RefCell::new(WaitingForValue) }
    }
    pub fn init(&self, value: T) {
        self.value.replace(Initialized(value));
    }
}

impl<T> Deref for Deferred<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        if let Initialized(value) = self.value.borrow().deref() {
            value
        } else {
            panic!("Deferred value must be initialized before the first usage")
        }
    }
}

但我有一个错误:

error[E0515]: cannot return value referencing temporary value
   |
30 |         if let Initialized(value) = self.value.borrow().deref() {
   |                                     ------------------- temporary value created here
31 |             value
   |             ^^^^^ returns a value referencing data owned by the current function

我尝试了不同的引用类型,但无法正常工作。

另外,我尝试过使用 unsafe 来做到这一点:

fn deref(&self) -> &Self::Target {
    unsafe {
        if let Initialized(value) = &*self.value.as_ptr() {
            &value
        } else {
            panic!("Deferred value must be initialized before the first usage")
        }
    }
}

它在这种情况下有效,但我不确定这个不安全的代码不会产生未定义的行为。

【问题讨论】:

    标签: rust


    【解决方案1】:

    您不能从 RefCell 返回共享引用,因为借用检查是在运行时通过 RefRefMut 进行的,这些包装器实现 as_ref&lt;Inner&gt; 但生成的引用归包装器所有 (@987654325 @/RefMut) 所以你必须把它放在独家新闻中。

    这使得特征 derefas_ref 不易使用,但您可以通过在 Value&lt;T&gt; 上实现 Deref 而不是 Deffered 来获得相同的行为,例如

    use std::{cell::{RefCell}, ops::{Deref}};
    
    pub struct Deferred<T> {
        value: RefCell<Value<T>>
    }
    
    pub enum Value<T> {
        Initialized(T),
        WaitingForValue
    }
    
    impl<T> Deferred<T> {
        pub fn init_later() -> Self {
            Self { value: RefCell::new(Value::WaitingForValue) }
        }
        pub fn init(&self, value: T) {
            self.value.replace(Value::Initialized(value));
        }
    }
    
    /// Implement deref on `Value` instead of `Deferred`
    impl<T> Deref for Value<T> {
        type Target = T;
    
        fn deref(&self) -> &Self::Target {
            if let Value::Initialized(value) = self {
                value
            } else {
                panic!("Deferred value must be initialized before a first usage")
            }
        }
    }
    
    fn main() {
        let val = Deferred::init_later();
        val.init(String::from("Hello, world !"));
        let _: &String = val.value.borrow().deref();
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 2021-08-02
      • 1970-01-01
      • 2016-04-05
      • 1970-01-01
      相关资源
      最近更新 更多