我有各种结构都实现相同的特征。我想在某种条件下分支,在运行时确定要实例化哪些结构。然后,无论我跟随哪个分支,我都希望从该特征调用方法。

在Rust中这可能吗?我希望实现类似以下的内容(无法编译):

trait Barks {
    fn bark(&self);
}

struct Dog;

impl Barks for Dog {
    fn bark(&self) {
        println!("Yip.");
    }
}

struct Wolf;

impl Barks for Wolf {
    fn bark(&self) {
        println!("WOOF!");
    }
}

fn main() {
    let animal: Barks;
    if 1 == 2 {
        animal = Dog;
    } else {
        animal = Wolf;
    }
    animal.bark();
}

最佳答案

是的,但不是那么容易。您在其中写的是animal应该是Barks类型的变量,但是Barks是一个特征;接口(interface)的描述。特性没有静态定义的大小,因为可以出现任何大小的类型和impl Barks。编译器不知道将animal多大。
您需要做的是添加一个间接层。在这种情况下,您可以使用Box,尽管您也可以使用诸如Rc或普通引用之类的东西:

fn main() {
    let animal: Box<dyn Barks>;

    if 1 == 2 {
        animal = Box::new(Dog);
    } else {
        animal = Box::new(Wolf);
    }

    animal.bark();
}
在这里,我在堆上分配了DogWolf,然后将其强制转换为Box<dyn Barks>。这有点像用C#或Java将对象强制转换为接口(interface),或者用C++将Dog*强制转换为Barks*
您也可以使用的一种完全不同的方法是枚举。您可能拥有enum Animal { Dog, Wolf },然后定义了impl Animal { fn bark(&self) { ... } }。取决于您是否需要一套完全开放式的动物和/或多种特征。
最后,请注意上面的“种类”。在Java/C#/C++中,有很多东西无法正常工作。例如,Rust没有向下转换(您不能从Box<dyn Barks>返回Box<Dog>,也不能从一个特征转换为另一个特征)。同样,这仅在特征是“对象安全”的情况下有效(不使用泛型,不使用selfSelf按值)。

关于rust - 是否允许多态变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28219519/

10-11 01:56