我有各种结构都实现相同的特征。我想在某种条件下分支,在运行时确定要实例化哪些结构。然后,无论我跟随哪个分支,我都希望从该特征调用方法。
在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();
}
在这里,我在堆上分配了Dog
或Wolf
,然后将其强制转换为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>
,也不能从一个特征转换为另一个特征)。同样,这仅在特征是“对象安全”的情况下有效(不使用泛型,不使用self
或Self
按值)。关于rust - 是否允许多态变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28219519/