【问题标题】:Automatically derive traits implementation for Arc自动派生 Arc 的特征实现
【发布时间】:2020-09-18 22:29:41
【问题描述】:

我有一个 trait 和一个 struct 来实现它。包裹在Arc中的struct可以调用trait的方法,但是Arc本身并没有实现:

use std::sync::Arc;

trait Foo{
    fn bar(&self);
}

struct A;

impl Foo for A{ 
    fn bar(&self){ }
}

fn test<A: Foo>(arc_a: Arc<A>){
    let foo_obj: & dyn Foo = &arc_a; //the trait bound `std::sync::Arc<A>: Foo` is not satisfied
}

以下代码可以正常工作:

use std::sync::Arc;

trait Foo{
    fn bar(&self);
}

struct A;

impl Foo for A{ 
    fn bar(&self){ }
}

impl<A> Foo for Arc<A> //Manually implemented
where
    A: Foo
{ 
    fn bar(&self){ self.bar() }
}

fn test<A: Foo>(arc_a: Arc<A>){
    let foo_obj: & dyn Foo = &arc_a;
}

有没有办法自动派生这种 trait 的实现?

【问题讨论】:

  • 您的意思是引用arc_a 还是引用它后面的Alet foo_obj: &amp;dyn Foo = &amp;*arc_a; 应该可以工作。但如果你的意思是另一回事,是的,你必须为Arc 实现它,特别是如果这是你想要的行为。

标签: rust traits reference-counting


【解决方案1】:

您必须手动实现它们。虽然您手动实现Foo for Arc&lt;A&gt; 似乎完全是微不足道的,但重要的部分是“隐藏”在self.bar() 中,其中自动取消引用从self: &amp;Arc&lt;A&gt;&amp;A。请记住,您的实现 Foo for Arc&lt;A&gt; 实际上可能完全不同;不过,在现实世界中,我们通常只需要“deref impl”。

在你的第一个例子中

fn test<A: Foo>(arc_a: Arc<A>){
    let foo_obj: &dyn Foo = &arc_a;
}

如果您执行= &amp;*arc_a,这将编译,因为*arc_a derefs 从Arc&lt;A&gt;A&amp;*arc_a 然后是&amp;dyn Foo

在您的第二个示例中,您提供了手动实现 for Arc&lt;A&gt;

impl<A> Foo for Arc<A> where A: Foo { 
    fn bar(&self){ self.bar() }
}

这里,deref - 上面是明确的 - 现在隐含在 self.bar() 中。这使您免于手动取消引用,但 impl 可能完全不同。例如:

impl Foo for A{ 
    fn bar(&self){ println!("This is fine") }
}

impl<A> Foo for Arc<A>
where
    A: Foo
{ 
    fn bar(&self) { panic!() }
}

fn test<A: Foo>(arc_a: Arc<A>){
    let foo_obj: & dyn Foo = &arc_a;
    foo_obj.bar()
}

fn main() {
    test(Arc::new(A))
}

上面的程序会恐慌,因为foo_obj 使用impl for Arc&lt;A&gt;。如果将test 中的行更改为= &amp;*arc_a,则使用impl for A,程序将打印“这很好”。

如果您只需要简单的 Foo 实现普通智能指针,您可以通过宏来实现:

macro_rules! deref_impl {
    ($($sig:tt)+) => {
        impl $($sig)+ {
            fn bar(&self) {
                (**self).bar()
            }
        }
    };
}
deref_impl!(<'a, N> Foo for &'a N where N: Foo + ?Sized);
deref_impl!(<'a, N> Foo for &'a mut N where N: Foo + ?Sized);
deref_impl!(<N> Foo for Box<N> where N: Foo + ?Sized);
deref_impl!(<N> Foo for std::rc::Rc<N> where N: Foo + ?Sized);
deref_impl!(<N> Foo for std::sync::Arc<N> where N: Foo + ?Sized);

【讨论】:

    猜你喜欢
    • 2020-05-09
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 2020-04-19
    • 2017-01-17
    • 1970-01-01
    相关资源
    最近更新 更多