trait Counter {
    fn count(&self) -> i32;
}

struct AddCounter {
    a: i32,
    b: i32,
}
impl Counter for AddCounter {
    fn count(&self) -> i32 {
        self.a + self.b
    }
}

struct MulCounter {
    a: i32,
    b: i32,
}
impl Counter for MulCounter {
    fn count(&self) -> i32 {
        self.a * self.b
    }
}

fn get_counter(a: i32, b: i32, op: &str) -> impl Counter {
    match op {
        "+" => AddCounter { a, b },
        "*" => MulCounter { a, b },
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

fn main() {}

我打get_counter(...)时出错:

error[E0308]: match arms have incompatible types
  --> src/main.rs:26:5
   |
26 | /     match op {
27 | |         "+" => AddCounter { a, b },
28 | |         "*" => MulCounter { a, b },
   | |                ------------------- match arm with an incompatible type
29 | |         _ => panic!(format!("{}{}", "未知的符号:", op)),
30 | |     }
   | |_____^ expected struct `AddCounter`, found struct `MulCounter`
   |
   = note: expected type `AddCounter`
              found type `MulCounter`

推荐答案

请将impl Trait符号视为泛型类型.你不能写:

fn get_counter<T>(a: i32, b: i32, op: &str) -> T {
    match op {
        "+" => AddCounter { a, b },
        "*" => MulCounter { a, b },
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

因为AddCounterMulCounter没有相同的类型:T是什么?

您可以使用动态分派而不是静态分派:

fn get_counter(a: i32, b: i32, op: &str) -> Box<dyn Counter> {
    match op {
        "+" => Box::new(AddCounter { a, b }),
        "*" => Box::new(MulCounter { a, b }),
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

进一步解释

当您使用静态分派时,Rust编译器会修改代码:它会为泛型类型的每个值生成一个新函数(有关详细信息,请参阅What is monomorphisation with context to C++?).每个返回值都是"真实"的普通类型.在这种情况下,函数不能返回(例如)一条路径中的String和另一条路径中的i32.

对于dynamic dispatch,返回的不是"实"类型,而是trait object:编译器不知道实类型;它只关心trait对象是否可以用作trait实现器.这就是你在这里需要的.

Rust相关问答推荐

Rust kill std::processs::child

在actix—web中使用Redirect或NamedFile响应

如何格式化传入Rust中mysql crate的Pool::new的字符串

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

告诉Rust编译器返回值不包含构造函数中提供的引用

如何使用Actix Web for Rust高效地为大文件服务

Rust ndarray:如何从索引中 Select 数组的行

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

为什么比较Option<;字符串>;具有常数Option<&;str>;需要显式类型转换吗?

为什么 `Deref` 没有在 `Cell` 上实现?

使用 serde::from_value 反序列化为泛型类型

`UnsafeCell` 在没有锁定的情况下跨线程共享 - 这可能会导致 UB,对吗?

如何限制 GtkColumnView 行数

Rust 为什么被视为borrow ?

Rust编译器通过哪些规则来确保锁被释放?

枚举的利基优化如何在 Rust 中工作?

使用自定义 struct 收集 Vec

是否有适当的方法在参考 1D 中转换 2D 数组

有没有办法在 Rust 中对 BigInt 进行正确的位移?

编写 TOML 文件以反序列化为 struct 中的枚举