我试图用RUST编写一个函数来构建不同类型的对象(所有相同特征的实现),但我遇到了麻烦,不知道我是在try 做一些非法的事情,还是只是没有掌握正确的语法. 以下是一个未编译的玩具样例(Animal_Factory函数的三个变体都没有编译):

enum Error {
    UnknownAnimal,
}

trait Animal {
    fn bark(&self);
}

struct Dog {}

impl Dog {
    fn new() -> Result<Dog, Error> {
        Ok(Dog {})
    }
}

impl Animal for Dog {
    fn bark(&self) {
        println!("Bau! Bau!");
    }
}

struct Cat {}

impl Cat {
    fn new() -> Result<Cat, Error> {
        Ok(Cat {})
    }
}

impl Animal for Cat {
    fn bark(&self) {
        println!("Meow! Meow!");
    }
}

/*
fn animal_factory(kind: &str) -> Result<impl Animal, Error> {
    match kind {
        "cat" => Cat::new(),
        "dog" => Dog::new(),
        _ => Err(Error::UnknownAnimal),
    }
}
*/

/*
fn animal_factory(kind: &str) -> Result<impl Animal, Error> {
    match kind {
        "cat" => {
            return Cat::new();
        },
        "dog" => {
            return Dog::new();
        },
        _ => {
            return Err(Error::UnknownAnimal);
        },
    }
}
*/

fn animal_factory(kind: &str) -> Result<impl Animal, Error> {
    if kind == "cat" {
        Cat::new()
    } else if kind == "dog" {
        Dog::new()
    } else {
        Err(Error::UnknownAnimal)
    }
}

fn main() {
    let x = animal_factory("cat").unwrap();
    let y = animal_factory("dog").unwrap();
}

有什么见解吗?也许我需要把东西装起来?

推荐答案

如果您try 返回不同的具体类型(在本例中为CatDog),则impl Animal将不起作用,即使两者都实现了Animal.从文档中:

这些类型代表另一个具体类型,在该类型中,调用方只能使用由指定特征声明的方法.

因此,try 返回CatDog不能将impl Animal作为返回类型,因为这两个具体类型之间的类型不匹配.

幸运的是,我们可以很容易地从CatDog实例创建一个同样实现Animal:trait objects的公共类型.特征对象使用dyn Animal而不是impl Animal进行注释.特征对象是动态调整大小的,因此我们需要将它们包装到Box或其他类型的(智能)指针或引用中:

fn animal_factory(kind: &str) -> Result<Box<dyn Animal>, Error> {
    if kind == "cat" {
        Ok(Box::new(Cat::new()?))
    } else if kind == "dog" {
        Ok(Box::new(Dog::new()?))
    } else {
        Err(Error::UnknownAnimal)
    }
}

Playground.

Rust相关问答推荐

有条件默认实现

为什么是!为Rust中的RwLockReadGuard和RwLockWriteGuard实现的发送特征?

是否可以为`T:Copy`执行`T. clone`的测试

访问Rust中的隐藏变量

将数组转换为HashMap的更简单方法

integer cast as pointer是什么意思

除了调用`waker.wake()`之外,我如何才能确保future 将再次被轮询?

为昂贵的for循环制作筛子

用于判断整数块是否连续的SIMD算法.

对于rustc编译的RISC-V32IM二进制文件,llvm objdump没有输出

由于生存期原因,返回引用的闭包未编译

为什么 tokio 在以奇怪的方式调用时只运行 n 个任务中的 n-1 个?

期望一个具有固定大小 x 元素的数组,找到一个具有 y 元素的数组

为什么 GAT、生命周期和异步的这种组合需要 `T: 'static`?

如何限制 GtkColumnView 行数

如何在 Rust 中打印 let-else 语句中的错误?

一次不能多次borrow *obj作为可变对象

Rust 1.70 中未找到 Trait 实现

`移动||异步移动{...}`,如何知道哪个移动正在移动哪个?

具有生命周期和以后引用的可变方法