【问题标题】:How can I implement Deref for a struct that holds an Rc<Refcell<Trait>>?如何为包含 Rc<Refcell<Trait>> 的结构实现 Deref?
【发布时间】:2019-09-09 14:29:27
【问题描述】:

我的目标是将针对我的结构的方法调用委托给 Trait 的方法,其中 Trait 对象位于 RcRefCell 中。

我尝试遵循这个问题的建议: How can I obtain an &A reference from a Rc<RefCell<A>>?

我得到一个编译错误。

use std::rc::Rc;
use std::cell::RefCell;
use std::fmt::*;
use std::ops::Deref;

pub struct ShyObject {
    pub association: Rc<RefCell<dyn Display>>
}

impl Deref for ShyObject {
    type Target = dyn Display;
    fn deref<'a>(&'a self) -> &(dyn Display + 'static) {
        &*self.association.borrow()
    }
}

fn main() {}

这是错误:

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:13:9
   |
13 |         &*self.association.borrow()
   |         ^^-------------------------
   |         | |
   |         | temporary value created here
   |         returns a value referencing data owned by the current function

我的示例使用Display 作为特征;实际上,我有一个带有十几种方法的特征。我试图避免必须实现所有这些方法的样板,而只是在每次调用中深入到 Trait 对象。

【问题讨论】:

标签: rust traits rc refcell


【解决方案1】:

你不能。 RefCell::borrow 返回 Ref&lt;T&gt;,而不是 &amp;T。如果您尝试在方法中执行此操作,则需要先借用 Ref&lt;T&gt;,但它会超出范围。

除了实现Deref之外,您还可以有一个方法来返回以下内容:

impl ShyObject {
    fn as_deref(&self) -> impl Deref<Target = dyn Display> {
        self.association.borrow()
    }
}

否则,由于无论如何您只想公开内部数据的 Display 实现,您可以通过实际取消引用不同的委托类型来解决它:

pub struct ShyObject {
    association: Assocation<dyn Display>,
}

struct Assocation<T: ?Sized>(Rc<RefCell<T>>);

impl<T: Display + ?Sized> fmt::Display for Assocation<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0.borrow())
    }
}

impl Deref for ShyObject {
    type Target = dyn Display + 'static;
    fn deref(&self) -> &Self::Target {
        &self.association
    }
}

【讨论】:

    【解决方案2】:

    你不能那样做。 borrow 创建a new struct 允许RefCell 跟踪借用。然后你就不能借用这个Ref,因为它是一个局部变量。

    【讨论】:

    • 是否有其他方法可以使用 Deref 来促进委派?一些有生命的魔法?
    • @PaulChernoch Lifetime 注解不会改变事物的寿命——它们只是向编译器描述你想要的生命周期约束。如果你想要不可能的约束,那么没有注释会有所帮助。
    • @PaulChernoch 不,根据定义你不能。
    猜你喜欢
    • 2021-04-06
    • 1970-01-01
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 2020-12-06
    • 2022-10-13
    • 2015-03-16
    • 2020-03-24
    相关资源
    最近更新 更多