如何解决如何在 Rust 中创建对通用特征对象的引用的 Vec?
我是 Rust 的新手。我的背景是Java。我正在尝试解决以下问题。
- 我有一个为
trait Fuel
和struct Diesel
实现的struct Gas
。 - 我还有一个带有
trait Vehicle
泛型类型参数的Fuel
。 Vehicle 是为struct Car<F: Fuel>
和struct Bus<F: Fuel>
实现的。
最后,我想把对可能的异构特征对象的引用放到一个 Vec
中,如下所示:
let diesel_car = Car { fuel: Diesel {} };
let gas_car = Car { fuel: Gas {} };
let diesel_bus = Bus { fuel: Diesel {} };
let gas_bus = Bus { fuel: Gas {} };
let garage = vec![
&diesel_car,&gas_car,&diesel_bus,&gas_bus
];
但是我得到这个编译错误:
error[E0308]: mismatched types
--> src/main.rs:63:9
|
63 | &gas_car,| ^^^^^^^^ expected struct `Diesel`,found struct `Gas`
|
= note: expected type `&Car<Diesel>`
found reference `&Car<Gas>`
这个 Vec 中引用的泛型类型应该是什么?它猜测它应该类似于 Vec<&dyn Vehicle>
。但是这个变体也不能编译,因为它想提前知道 Vehicle
的泛型类型参数。在 Java 中,我只会写 List<Vehicle<?>
。 Rust 中有没有类似的东西?
整个示例在 playground 中可用。
附言我显然可以从 Vehicle
中删除一个通用参数并将其替换为 Box<dyn Fuel>
,但我想通过动态调度来最小化位置。
解决方法
但是这个变体也不能编译,因为[编译器]想提前知道Vehicle
的泛型类型参数。
我认为您在这里混淆了静态调度和动态调度。我认为您也混淆了您要求编译器做什么与您期望它做什么。很明显,您想要动态调度,但您正在尝试使用泛型来实现它,这是不可能的,因为泛型是纯粹的编译时抽象,并且总是会产生静态调度代码。 “泛型”在运行时不存在,也不存在于最终的二进制文件中。如果您想要“运行时泛型”,这就是特征对象和动态分派的用途。
在 Java 中,我只会写 List<Vehicle<?>>
。 Rust 中有没有类似的东西?
是的,将 F: Fuel
泛型类型参数替换为 dyn Fuel
特征对象。
附言我显然可以从 Vehicle
中删除一个通用参数并将其替换为 Box<dyn Fuel>
,但我想通过动态调度来最小化位置。
但是你只是问如何在 Rust 中实现 Java 等价物,而这正是 Java 解决这个问题的方式:通过使用动态调度。你不能吃你的蛋糕也吃它。如果你想要静态调度的速度,那意味着也要接受静态调度的约束。如果这些约束对您的程序来说太严格,那么您应该使用 trait 对象和动态调度。
Rust 的枚举可能是最接近你想要的。它们是泛型和 trait 对象之间的一个很好的折衷,为您提供(几乎)前者的速度,同时为您提供后者的灵活性。这是您重构为使用枚举的示例:
enum Fuel {
Diesel,Gas,}
impl Fuel {
fn efficiency(&self) -> f64 {
match self {
Fuel::Diesel => 0.9,Fuel::Gas => 0.8,}
}
}
enum Vehicle {
Car(Fuel),Bus(Fuel)
}
impl Vehicle {
fn mass(&self) -> f64 {
match self {
Vehicle::Car(_) => 1000.0,Vehicle::Bus(_) => 5000.0,}
}
}
fn main() {
let diesel_car = Vehicle::Car(Fuel::Diesel);
let gas_car = Vehicle::Car(Fuel::Gas);
let diesel_bus = Vehicle::Bus(Fuel::Diesel);
let gas_bus = Vehicle::Bus(Fuel::Gas);
let garage = vec![
&diesel_car,&gas_car,&diesel_bus,&gas_bus
];
}
,
不能将不同的类型放在同一个向量中。 但是,使用枚举,您可以在不需要不同类型的情况下获得所需的功能。
由于您有 2 种燃料变体,它们的枚举将如下所示:
pub enum Fuel {
Diesel,}
然后添加一个函数 efficiency
来返回每个燃料变体的效率:
impl Fuel {
fn efficiency(&self) -> f64 {
match self {
Fuel::Diesel => 0.9,}
}
}
您现在有 2 种相同类型的燃料。
在对车辆执行相同操作后(您也有它们的 2 个变体),您可以将各种组合添加到同一个向量中。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。