是否允许多态变量? [英] Are polymorphic variables allowed?
问题描述
我有各种结构体,它们都实现了相同的特征.我想在某些条件下进行分支,在运行时决定要实例化哪些结构.然后,无论我遵循哪个分支,我都想从那个特征调用方法.
I have various structs that all implement the same trait. I want to branch on some condition, deciding at runtime which of those structs to instantiate. Then, regardless of which branch I followed, I want to call methods from that trait.
这在 Rust 中可行吗?我希望实现如下(无法编译):
Is this possible in Rust? I'm hoping to achieve something like the following (which does not compile):
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
是一个特征;接口的描述.特征没有静态定义的大小,因为任何大小的类型都可能出现并且 impl Barks
.编译器不知道animal
有多大.
Yes, but not that easily. What you've written there is that animal
should be a variable of type Barks
, but Barks
is a trait; a description of an interface. Traits don't have a statically-defined size, since a type of any size could come along and impl Barks
. The compiler has no idea how big to make animal
.
您需要做的是添加一个间接层.在这种情况下,您可以使用 Box
,但您也可以使用诸如 Rc
或普通引用之类的东西:
What you need to do is add a layer of indirection. In this case, you can use Box
, although you can also use things like Rc
or plain references:
fn main() {
let animal: Box<dyn Barks>;
if 1 == 2 {
animal = Box::new(Dog);
} else {
animal = Box::new(Wolf);
}
animal.bark();
}
在这里,我在堆上分配 Dog
或 Wolf
,然后将其转换为 Box
.这有点像在 C# 或 Java 中将对象转换为接口,或者在 C++ 中将 Dog*
转换为 Barks*
.
Here, I'm allocating the Dog
or Wolf
on the heap, then casting that up to a Box<dyn Barks>
. This is kind of like casting an object to an interface in something like C# or Java, or casting a Dog*
to a Barks*
in C++.
您还可以使用一种完全不同的方法是枚举.你可以有 enum Animal { Dog, Wolf }
然后定义一个 impl Animal { fn bark(&self) { ... } }
.取决于您是否需要一组完全开放的动物和/或多种特征.
An entirely different approach you could also use would be enums. You could have enum Animal { Dog, Wolf }
then define an impl Animal { fn bark(&self) { ... } }
. Depends on whether you need a completely open-ended set of animals and/or multiple traits.
最后,请注意种类"以上.有很多东西不能像在 Java/C#/C++ 中那样工作.例如,Rust 没有向下转换(你不能从 Box
回到 Box
,或者从一个特性到另一个特性).此外,这仅在特征是对象安全"的情况下才有效.(没有泛型,没有使用 self
或 Self
by-value).
Finally, note that "kind of" above. There are various things that don't work as they would in Java/C#/C++. For example, Rust doesn't have downcasting (you can't go from Box<dyn Barks>
back to Box<Dog>
, or from one trait to another). Also, this only works if the trait is "object safe" (no generics, no using self
or Self
by-value).
这篇关于是否允许多态变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!