我有各种结构,都实现相同的特征.我想在某些条件下进行分支,在运行时决定实例化哪些结构.然后,无论我遵循哪个分支,我都想从该特征中调用方法.
这可能在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();
}
Run Code Online (Sandbox Code Playgroud)
DK.*_*DK. 17
是的,但不是那么容易.你在那里写的是animal
应该是一个类型的变量Barks
,但它Barks
是一个特征; 接口的描述.特征没有静态定义的大小,因为任何大小的类型都可以出现impl Barks
.编译器不知道要做多大animal
.
您需要做的是添加一个间接层.在这种情况下,你可以使用Box
,虽然你也可以使用像Rc
或简单的引用:
fn main() {
let animal: Box<Barks>;
if 1 == 2 {
animal = Box::new(Dog);
} else {
animal = Box::new(Wolf);
}
animal.bark();
}
Run Code Online (Sandbox Code Playgroud)
在这里,我正在分配Dog
或Wolf
在堆上,然后将其转换为Box<Barks>
.这有点像将对象转换为类似C#或Java的接口,或者在C++中转换Dog*
为a Barks*
.
您可以使用的完全不同的方法是枚举.你可以enum Animal { Dog, Wolf }
定义一个impl Animal { fn bark(&self) { ... } }
.取决于您是否需要一套完全开放的动物和/或多种特征.
最后,请注意上面的"种类".有些东西不像Java/C#/ C++那样有效.例如,Rust没有向下转换(你不能从Box<Barks>
后面去Box<Dog>
,或从一个特征到另一个特征).此外,这仅在特征是"对象安全"(没有泛型,没有使用self
或Self
按值)时才有效.
She*_*ter 16
DK有一个很好的解释,我将简单介绍一下我们在堆栈上分配Dog
或者Wolf
堆栈的示例,避免堆分配:
fn main() {
let dog;
let wolf;
let animal: &Barks;
if 1 == 2 {
dog = Dog;
animal = &dog;
} else {
wolf = Wolf;
animal = &wolf;
}
animal.bark();
}
Run Code Online (Sandbox Code Playgroud)
它有点难看,但引用完成了相同的间接性,而且Box
开销较小.
定义自定义枚举是执行此操作的最有效方法。这将允许您在堆栈上准确分配所需的空间量,即最大选项的大小,加上 1 个额外字节来跟踪存储哪个选项。与使用 aBox
或 trait 引用的解决方案不同,它还允许直接访问而无需间接级别。
不幸的是,它确实需要更多样板:
enum WolfOrDog {
IsDog(Dog),
IsWolf(Wolf)
}
use WolfOrDog::*;
impl Barks for WolfOrDog {
fn bark(&self) {
match *self {
IsDog(ref d) => d.bark(),
IsWolf(ref w) => w.bark()
}
}
}
fn main() {
let animal: WolfOrDog;
if 1 == 2 {
animal = IsDog(Dog);
} else {
animal = IsWolf(Wolf);
}
animal.bark();
}
Run Code Online (Sandbox Code Playgroud)
在main
我们只使用一个堆栈分配的变量,保存我们自定义枚举的一个实例。
归档时间: |
|
查看次数: |
655 次 |
最近记录: |