我有一个特质,可以称为
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();
}
编译器为您提供了有关此的多个提示,如果您全部遵循它们,您将得到类似这样的内容,它确实可以编译:
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();
}