将性状 T 的 Rc<Self> 转换为 Rust 中的 Rc<T>

问题描述 投票:0回答:1

我有一个特质,可以称为

T
。我目前在很多地方使用
Rc<dyn T>
。 问题是我想向
T
添加一个默认方法来运行所需的函数
Rc<dyn T>
。但据我所知,没有办法投射
Rc<Self>
,因为自我的大小并不取决于特质。我无法让整个项目使用泛型,那么我该如何解决这个问题呢?
示例:

use std::rc::Rc;
trait T {
    fn run_test_method(self: Rc<Self>) {
        test_method(self);
    }
}

struct A;
impl T for A {}

fn test_method(_rc: Rc<dyn T>) {
    // do stuff with 'rc'
}
fn main() {
    let a = Rc::new(A);
    a.run_test_method();
}
rust casting traits
1个回答
2
投票

编译器为您提供了有关此的多个提示,如果您全部遵循它们,您将得到类似这样的内容,它确实可以编译:

trait T {
    fn run_test_method(self: Rc<Self>)
    where
        Self: Sized + 'static,
    {
        test_method(self);
    }
}

需要

Sized
边界,以便可以执行转换,并且需要
'static
边界,因为
dyn T
参数中的
test_method
没有生命周期,这使得它隐式
dyn T + 'static

如果出于某种原因您不能要求

'static
生命周期(因为
T
的实现者包含非静态借用),那么您可以删除
'static
上的
T::run_test_method
绑定(如果您指示
dyn T
)可以在
test_method
:

上拥有非静态生命周期
fn test_method(_rc: Rc<dyn T + '_>) {
    // do stuff with 'rc'
}

如果您希望能够使用

Rc<A>
Rc<dyn T>
来调用此方法,那么您必须将其实现为两个单独的方法,因为从根本上来说,每个方法都会执行不同的操作。一个将大小值转换为特征对象,而另一个则不这样做。

您可以通过使用针对这两种情况实现的辅助特征来实现此目的。 (这里的类型名称对于经常使用 Rust 工作的人来说会有点混乱,因为

T
通常是泛型类型,但这里它是一个特征。)

// Remove the method from this type.
trait T {}

trait RunTestMethod {
    fn run_test_method(self);
}

impl<X: T + Sized> RunTestMethod for Rc<X> {
    fn run_test_method(self) {
        test_method(self);
    }
}

impl RunTestMethod for Rc<dyn T> {
    fn run_test_method(self) {
        test_method(self);
    }
}

现在,你可以这样做:

fn main() {
    let a = Rc::new(A);
    Rc::clone(&a).run_test_method();
    
    let b: Rc<dyn T> = a;
    b.run_test_method();
}
© www.soinside.com 2019 - 2024. All rights reserved.