克隆一个 Rc<RefCell<MyType> 特征对象并施放它
Clone an Rc<RefCell<MyType> trait object and cast it
此问题与
相关
假设我有这段代码可以正常工作:
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
的类型,它实现了 TraitA
和 TraitB
。
- 目标是让特征对象
TraitA
能够转换为 TraitB
,反之亦然。
- 所以我使用了一个包含进行转换的方法的超特性。
- 这非常适合
std::Rc
智能指针。
到目前为止一切顺利。但是现在我需要 a
和 b
的可变引用,但是由于 a
和 b
实际上是相同类型的实例,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>>
对于自参数。
所以,主要问题是:有没有办法将 Rc<RefCell<TraitA>>
转换为 Rc<RefCell<TraitB>
?
谢谢
您可以通过 not 在 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
实现都是相同的。要使此实现可用于实现 TraitA
和 TraitB
的所有类型,您可以使用泛型 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
因为函数 return 类型中的特征对象具有隐式 'static
生命周期限制。
此问题与
假设我有这段代码可以正常工作:
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
的类型,它实现了TraitA
和TraitB
。 - 目标是让特征对象
TraitA
能够转换为TraitB
,反之亦然。 - 所以我使用了一个包含进行转换的方法的超特性。
- 这非常适合
std::Rc
智能指针。
到目前为止一切顺利。但是现在我需要 a
和 b
的可变引用,但是由于 a
和 b
实际上是相同类型的实例,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>>
对于自参数。
所以,主要问题是:有没有办法将 Rc<RefCell<TraitA>>
转换为 Rc<RefCell<TraitB>
?
谢谢
您可以通过 not 在 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
实现都是相同的。要使此实现可用于实现 TraitA
和 TraitB
的所有类型,您可以使用泛型 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
因为函数 return 类型中的特征对象具有隐式 'static
生命周期限制。