是否允许多态变量? [英] Are polymorphic variables allowed?

查看:28
本文介绍了是否允许多态变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有各种结构体,它们都实现了相同的特征.我想在某些条件下进行分支,在运行时决定要实例化哪些结构.然后,无论我遵循哪个分支,我都想从那个特征调用方法.

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();
}

在这里,我在堆上分配 DogWolf,然后将其转换为 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,或者从一个特性到另一个特性).此外,这仅在特征是对象安全"的情况下才有效.(没有泛型,没有使用 selfSelf 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆