casting - 克隆一个 Rc<RefCell<MyType> 特征对象并转换它

标签 casting rust traits

这个问题与Rust: Clone and Cast Rc pointer有关

假设我有这段代码可以正常工作:

use std::rc::Rc;

trait TraitAB : TraitA + TraitB {
    fn as_a(self: Rc<Self>) -> Rc<dyn TraitA>;
    fn as_b(self: Rc<Self>) -> Rc<dyn TraitB>;
}

trait TraitA {}
trait TraitB {}

struct MyType {}

impl TraitAB for MyType {
    fn as_a(self: Rc<Self>) -> Rc<dyn TraitA> {self}
    fn as_b(self: Rc<Self>) -> Rc<dyn TraitB> {self}
}

impl TraitA for MyType {}
impl TraitB for MyType {}

fn main() {
    let a: Rc<dyn TraitA>;
    let b: Rc<dyn TraitB>;
    {
        let mut ab: Rc<dyn TraitAB> = Rc::new(MyType{});
        a = ab.clone().as_a();
        b = ab.clone().as_b();
    }
    // Use a and b.
}

稍微解释一下代码:

  • 我的类型叫做 MyType实现TraitATraitB .
  • 目标是拥有一个特质对象TraitA能够被类型转换到TraitB反之亦然。
  • 所以我使用了一个超特征来保存进行转换的方法。
  • 这非常适合 std::Rc智能指针。

到目前为止一切顺利。但现在我需要 a 的可变引用和 b , 但自 ab实际上是相同类型的实例,Rust 不会让我拥有同一事物的 2 个可变引用。

因此,此类问题的常见模式是 std::cell::RefCell .

注意:我相信这种模式在这种特殊情况下是正确的,因为这是一个常见的内部可变性问题。我不愿意实际更改引用,而只是更改类型的内部状态。

因此,按照这个想法,我更改了以下几行:

trait TraitAB : TraitA + TraitB {
    fn as_a(self: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitA>>;
    fn as_b(self: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitB>>;
}
//...
let mut ab: Rc<RefCell<dyn TraitAB>> = Rc::new(RefCell::new(MyType{}));

但是这个更改不会编译。看了一番,发现self只能是:

  • self: Self // self
  • self: &Self // &self
  • self: &mut Self // &mut self
  • self: Box<Self> // No short form
  • self: Rc<Self> // No short form / Recently supported

所以这意味着我不能使用

self: Rc<RefCell<Self>>

对于 self 参数。

所以,主要问题是:有没有办法转换 Rc<RefCell<TraitA>>Rc<RefCell<TraitB> ? 谢谢

最佳答案

您可以通过TraitAB 的转换方法中使用接收器来解决此问题(即通过将它们声明为关联函数) :

trait TraitAB : TraitA + TraitB {
    fn as_a(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitA>>;
    fn as_b(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitB>>;
}

然后可以将特征实现为

impl TraitAB for MyType {
    fn as_a(it: Rc<RefCell<MyType>>) -> Rc<RefCell<dyn TraitA>> {it}
    fn as_b(it: Rc<RefCell<MyType>>) -> Rc<RefCell<dyn TraitB>> {it}
}

然后可以使用完全限定语法调用这些函数。

a = TraitAB::as_a(ab.clone());
b = TraitAB::as_b(ab.clone());

所有类型的 TraitAB 实现都是相同的。要使此实现可用于所有实现 TraitATraitB 的类型,您可以使用通用的 impl:

impl<T: TraitA + TraitB + 'static> TraitAB for T {
    fn as_a(it: Rc<RefCell<T>>) -> Rc<RefCell<dyn TraitA>> {it}
    fn as_b(it: Rc<RefCell<T>>) -> Rc<RefCell<dyn TraitB>> {it}
}

请注意 T: 'static 因为函数返回类型中的特征对象具有隐式的 'static 生命周期界限。

Playground

关于casting - 克隆一个 Rc<RefCell<MyType> 特征对象并转换它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55959384/

相关文章:

scala - 为什么 Scala API 有两种组织类型的策略?

java - 转换或使用重载方法是更好的做法吗?

c++ - 从自定义类到内置类型的转换

rust - 将工作代码提取到单独的函数中时的生命周期问题

websocket - 为变形过滤器重用已移动的变量

rust - 如何为具有 "rented"引用的类型实现特征

java - 转换到 jar 类

java - 将对象转换为子类型时找不到符号

返回 Vec<&str> 时字符串的生命周期

php - 不能使用 Illuminate\Contracts\Auth\Authenticatable - 这不是一个特征