返回对Box <dyn Trait>的引用

时间:2020-04-18 22:47:39

标签: rust

这个周末开始学习生锈,我正在尝试在我的课堂上写一个私有的助手方法来查找一些内部值,但是事实证明这很复杂。我有一些实现特质的结构:

trait Animal {}

struct Dog {}
impl Dog for Animal{}

struct Cat{}
impl Cat for Animal{}

以及一个容纳多种动物变种的容器:

struct Person {
  my_dog: Dog,
  my_cat: Cat
}

我想做的是编写一个帮助程序,查找适当的动物,如下所示:

impl Person {
  fn look_up_animal(&self, animal_name: &str) -> Box<&dyn Animal> {
    match animal_name {
      "dog" => Box::from(&self.my_dog),
      "cat" => Box::from(&self.my_cat)
    }
  }
}

不幸的是,我无法弄清楚如何为此做类型。上面使用引用 Box的版本给出了类似“预期struct Box<&dyn Animal>但得到struct Box<&Dog>的错误,因此我不确定如何转换常规值变成dyn值。

2 个答案:

答案 0 :(得分:5)

您想要的内容的完全明确的版本

impl Person {
    fn look_up_animal(&self, animal_name: &str) -> Option<Box<&dyn Animal>> {
        match animal_name {
            "dog" => Some(Box::from(&self.my_dog as &dyn Animal)),
            "cat" => Some(Box::from(&self.my_cat as &dyn Animal)),
            _ => None,
        }
    }
}

Rust能够强制对特征对象进行一层引用,但是两层引用(Box&)都会使其崩溃。 (在Box中包含引用也会触发clippy警告。)这提出了另一种解决方案。

impl Person {
    fn look_up_animal(&self, animal_name: &str) -> Option<&dyn Animal> {
        match animal_name {
            "dog" => Some(&self.my_dog as &dyn Animal),
            "cat" => Some(&self.my_cat as &dyn Animal),
            _ => None,
        }
    }
}

这一次,由于仅存在一层引用,因此不需要显式强制转换as &dyn Animal

impl Person {
    fn look_up_animal(&self, animal_name: &str) -> Option<&dyn Animal> {
        match animal_name {
            "dog" => Some(&self.my_dog),
            "cat" => Some(&self.my_cat),
            _ => None,
        }
    }
}

(playground link)


注意:我添加了Option,以便在animal_name不是"dog""cat"时有返回的内容。您也可能会惊慌或默认使用其他实现Animal的东西。

答案 1 :(得分:-4)

<input type="file" />

完整解决方案playground

相关问题