【问题标题】:Get Rc<RefCell<dyn T>>> on a sub-type在子类型上获取 Rc<RefCell<dyn T>>>
【发布时间】:2020-10-16 21:30:09
【问题描述】:

我有以下定义:

trait A {
    fn f(&self);
}

trait B: A {
// ...
}

我想实现这种功能:

fn convert(v: Rc<RefCell<dyn B>>) -> Rc<RefCell<dyn A>> {
}

我希望有一种方法可以返回共享同一对象的值,这意味着使用以下声明:

let x: Rc<RefCell<dyn B>> /* = ... */;
let y = convert(Rc::clone(&x));

调用x.f()y.f() 将调用应用于同一个对象。

我如何实现函数convert 或如何更改类型定义以具有那种行为和那种转换(到子对象的转换)。

【问题讨论】:

  • Clone an Rc<RefCell<MyType> trait object and cast it 是大致相同的问题,但接受的答案并不能真正解决问题。
  • 是的@trentcl,这确实解决了问题,因为 TraitAB 不能成为特征对象(导致方法签名中的 Self),但我很欣赏这个想法。

标签: rust subtyping trait-objects


【解决方案1】:

Rust 不支持直接向上转换 trait 对象。由于 trait 对象的实现方式,如果没有运行时额外的工作,这是不可能的,因此 Rust 让你自己完成工作。

你可以这样做,例如

use std::rc::Rc;
use std::cell::RefCell;

trait A {
  fn f(&self) -> i32;
}

trait B: A {
}

struct Wrapper(Rc<RefCell<dyn B>>);

impl A for Wrapper {
    fn f(&self) -> i32 {
        A::f(&*self.0.borrow())
    }
}

fn convert(v: Rc<RefCell<dyn B>>) -> Rc<RefCell<dyn A>> {
    Rc::new(RefCell::new(Wrapper(v)))
}

【讨论】:

  • 是的,好主意。但它漏掉了一点,convert 的返回值必须引用作为v 参数传递的对象。但我知道该怎么做,我将使用包装器的这个想法,但通过重新实现 Rc 类型(引用计数器),以便让函数 convert 返回相同的引用。
  • """ convert 的返回值必须引用作为v 参数传递的对象""" 如果您的意思是我们应该将v 重新解释为Rc&lt;RefCell&lt;dyn A&gt;&gt;,即 不可能因为他们真的,真的不是一回事。如果您确实需要dyn A(而不仅仅是A),您有一个中间值,原因与fn convert(v: i32) -&gt; String {...} 必须有一个中间值相同。他们真的,真的不是一回事。
【解决方案2】:

感谢您的想法,我决定通过避免使用 trait-object 作为函数 convert in 根据 Rust 规则的参数来进行折衷:

use std::rc::Rc;
use std::cell::RefCell;

trait A {
    fn print(&self);
}

trait B: A {
}

trait Convert {
    fn convert(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn A>>;
}

struct MyType(u32);

impl Convert for MyType {
    fn convert(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn A>> {it}
}

impl A for MyType {
    fn print(&self) {
        println!("MyType({}) as A", self.0);
    }
}

impl B for MyType {}

fn main() {
    let a: Rc<RefCell<dyn A>>;
    {
        let b = Rc::new(RefCell::new(MyType(3)));
        a = Convert::convert(b.clone());
    }

    a.borrow().print();
}

Playground

【讨论】:

  • 此代码没有按照您在原始帖子中的要求执行 - 尝试执行 let b: Rc&lt;RefCell&lt;dyn B&gt;&gt; = Rc::new(RefCell::new(MyType(3)))(您遇到的第一个错误是 MyType 不包含 B,但如果你修复了,你会发现这种方法不能满足你在问题中的要求)
  • @MikeGraham 是的,我知道这段代码不能满足你在原始 pos 中的要求,我写的是妥协。 Rust 不能做我想做的事(无法将 RefCell&lt;dyn B&gt; 传递给 RefCell&lt;dyn A&gt;)导致差异。
  • 本代码除了定义B外,不涉及BMyType 甚至不包含 B
  • 感谢@MikeGraham,我修改了MyType 以实现B
猜你喜欢
  • 2020-05-26
  • 2021-04-06
  • 2019-12-13
  • 1970-01-01
  • 2023-01-20
  • 1970-01-01
  • 1970-01-01
  • 2020-01-15
相关资源
最近更新 更多