首页 > 解决方案 > 如何在 rust 中解决这个继承问题?

问题描述

首先是强制性的“我是 Rust 新手”:我是。

所以我有以下问题:

我有两个(或更多)数据结构,除了它们自己的行为之外,它们都实现了一些常见的行为。我有这些结构的列表(或者更确切地说:“超类型”),我需要访问它们的一些共享行为和它们的一些个人行为。我的问题是:我如何在 Rust 中做到这一点。

为了进一步说明我的问题,我提出了 Kotlin 和 Rust 之间的代码比较。Kotlin 可以按我的意愿工作,Rust 还没有。

在 Kotlin 中,代码可能如下所示(使用普通的、旧的继承抽象):

interface Animal {
    fun eat()
    fun sleep()
}
class Cat(val name: String) : Animal {
    fun meow()              { println("meow") }

    override fun eat()      { println("cat $name is eating fish(or lasagne)") }
    override fun sleep()    { println("cat $name sleeps inside") }
}
class Lion(val tag_id: Int) : Animal {
    fun roar()              { println("roar") }

    override fun eat()      { println("lion(tag=${tag_id} is eating gazelle") }
    override fun sleep()    { println("lion(tag=${tag_id} sleeps outside") }
}

var animals: MutableList<Animal> = ArrayList()
fun main() {
    animals.add(Cat("Garfield"))
    animals.add(Lion(12))
    //later:
    for (animal in animals) {
        animal.sleep()
        if (animal is Lion)
            animal.roar()
    }
}

在 Rust 中,我提出了以下代码(不允许使用“instance_of”类型的函数):

trait Animal {
    fn eat(&self);
    fn sleep(&self);
}

struct Cat {
    name: String
}
impl Cat {
    fn meow(&self)      { println!("meow") }
}
impl Animal for Cat {
    fn eat(&self)       { println!("cat {} is eating fish(or lasagne)", self.name) }
    fn sleep(&self)     { println!("cat {} sleeps inside", self.name) }
}

struct Lion {
    tag_id: usize
}
impl Lion {
    fn roar(&self)      { println!("roar") }
}
impl Animal for Lion {
    fn eat(&self)       { println!("lion(tag={}) is eating fish(or lasagne)", self.tag_id) }
    fn sleep(&self)     { println!("lion(tag={}) sleeps inside", self.tag_id) }
}

fn main() {
    let animals:Vec<Box<dyn Animal>> = vec![
                Box::new(Cat {name: "Garfield".to_string()}),
                Box::new(Lion {tag_id: 12})
    ];
    //later:
    for animal in animals {
        animal.sleep()
        //HOW DO I ACCESS THE CONCRETE STRUCT HERE?
    }
}

操场

我意识到这可能是一个愚蠢的问题,或者表明我“仍然被困在非 Rust 思维中”,但我在这里陷入了困境,只需要一点帮助。

标签: kotlininheritancerust

解决方案


尝试用组合来代替

trait Animal {
    fn voicebox(&self) -> Voicebox;
}
enum Voicebox {
    CatVoicebox, LionVoicebox
}

impl Voicebox {
    fn make_sound(&self) {
        match *self {
            Voicebox::CatVoicebox => println!("meow"),
            Voicebox::LionVoicebox => println!("roar!")
        }
    }
}

impl Animal for Cat {
    fn voicebox(&self) -> Voicebox {
      Voicebox::CatVoicebox
    }
}

impl Animal for Lion {
    fn voicebox(&self) -> Voicebox {
        Voicebox::LionVoicebox
    }
}

fn main() {
    let animals:Vec<Box<dyn Animal>> = vec![Box::new(Cat {name: "Garfield".to_string()}), Box::new(Lion {tag_id: 12})];
    //later:
    for animal in animals {
        animal.sleep();
        match animal.voicebox() {
            vb@Voicebox::LionVoicebox => vb.make_sound(),
            _ => ()
        }
    }
}

输出:

cat Garfield sleeps inside
lion(tag=12) sleeps inside
roar!

锈操场


推荐阅读