如何在转换为trait对象时使用Rc::clone?

4
《Rust编程之道》指出,在处理类型的值时,使用Rc::clone(&x)而不是x.clone()是惯用法,这样可以清楚地表明这不是您通常使用的clone函数。我完全赞同这种做法,但在实践中却遇到了困难。
我想要克隆一个引用计数的结构体,并将其转换为一个特质对象。使用rc.clone()可以完成此操作,但使用Rc::clone(&rc)却不能。这对我来说有点奇怪。
struct ListView {}
trait View {}
impl View for ListView {}

fn very_contrived_example() {
    let list_view: Rc<ListView> = Rc::new(ListView {});
    let mut views: Vec<Rc<dyn View>> = Vec::new();

    // Using Rc::clone does not work:

    // error[E0308]: mismatched types
    //
    // views.push(Rc::clone(&list_view));
    //                      ^^^^^^^^^^ expected trait object `dyn View`, found struct `ListView`
    //
    // note: expected reference `&Rc<dyn View>`
    //          found reference `&Rc<ListView>`

    // Using a cast works in this very contrived example, but has the
    // disadvantage of moving `list_view`, for some reason, which is not
    // acceptable in general:
    // views.push(Rc::clone(&(list_view as Rc<dyn View>)));

    // But invoking it using method syntax works fine, without a move:
    views.push(list_view.clone());
}

Rc::clone(&x)x.clone() 之间有什么区别?x.clone() 实际上调用了哪个函数?self 的类型是什么?我能直接调用它吗?

如何以惯用方式编写这段代码?

1个回答

7
这是类型推断的罕见失败。显式传递正确的显示类型可以解决问题:
views.push(Rc::<ListView>::clone(&list_view))

问题在于Rc::clone(&list_view)推断出Rc<T>中的T取决于期望的类型(即Rc<dyn View>),而非参数类型。另一方面,当你调用list_view.clone()时,它使用list_view类型上的Clone实现,因此解析为Rc::<ListView>::clone
如果您的代码中经常出现上述问题,并且您想保持正常克隆和弱引用浅层克隆之间的视觉区别,您可以编写一个小的帮助者 trait:
trait RcClone : Clone {
    fn rc_clone(&self) -> Self {
        self.clone()
    }
}

impl<T: ?Sized> RcClone for Rc<T> { }
impl<T: ?Sized> RcClone for Arc<T> { }

那么在你的代码中,你可以编写 list_view.rc_clone() ,它只适用于引用计数类型。这仍然表明与常规的 clone 不同的语义,同时不会出现类型推断问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接