为另一个特征实现一个特征是什么意思?

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

我读了此answer,但我仍然感到困惑。

  1. 您如何解释impl B for dyn A {}

    trait A {
        fn method_a(&self) {
            println!("a");
        }
    }
    
    trait B {
        fn method_b(&self) {
            println!("b")
        }
    }
    
    impl B for dyn A {}
    
    impl A for i32 {}
    
    fn main() {
        let x: &dyn A = &10;
        x.method_b();
    }
    

    Playground

    我可以理解impl A for i32 {},因为i32是具体类型。 dyn A不是具体类型(无大小,无法按值传递),您不能声明dyn A,而只能声明&dyn A。我应该解释

    // x.method_b();
    (*x).method_b();
    

    因为*xdyn A

  2. 我也可以声明impl B for &dyn A {},为什么我需要impl B for dyn A {}?用例是什么?

  3. 跟进:如果我修改代码

    fn main() {
        let x: &dyn A = &10;
        // have a B trait object over dyn A since
        // dyn A implements B
        let y: &dyn B = x;  
    }
    

    它将失败,并抱怨&dyn A不是&dyn B。我知道这是一个合理的抱怨,但是我为编译器提供了使用impl B for dyn A {}的选项。显然,编译器不认为这是一个选项。

rust traits
1个回答
0
投票

您不能声明dyn A,但是可以声明&dyn A,因为dyn A是特征对象type,而&dyn A是类型T的实例的pointer实现A

历史上,特征可以用作类型和特征。例如,它们都可以工作:

// Where B and A are traits
impl B for A {}
impl B for dyn A {}

[基本上,dyn A只是A的糖,以便更清楚地表明它打算用作特征对象类型。

&dyn A是指向T类型的实例的指针实例,该实例实现A和虚拟方法表(vtable),其中包含A实现的所有方法包。当类型为T的实例稍后在运行时调用T的实现时,必须执行此vtable查找。

因此,A是未调整大小的类型,而dyn A是具有已知大小的指针。

&dyn A类型的特质对象必须从指针强制转换为用作实现dyn A的具体类型。例如,在代码示例中,可以将A强制转换为i32

dyn A

或者可以通过函数强制:

impl B for dyn A {}

impl A for i32 {}

fn main() {
    let x: i32 = 10;
    (&x as &dyn A).method_a(); 
    (&x as &dyn A).method_b();
}

因为特征是动态大小类型(DST),要将它们用作特征对象,我们必须将它们放在某种指针之后,例如fn dispatch(a: &dyn A) { a.method_b(); } &dyn A,以便它可以指向可变大小的值并访问vtable调用已实现的方法。

另请参见:Box<dyn A>

© www.soinside.com 2019 - 2024. All rights reserved.