[英]How to create Vec of references to generic trait objects in Rust? [duplicate]
我是 Rust 的新手。 我的背景是 Java。 我正在尝试解决以下问题。
struct Diesel
和struct Gas
实现的trait Fuel
。Fuel
泛型类型参数的trait Vehicle
。 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有类似的吗?
整个示例可在操场上找到。
PS 我显然可以从Vehicle
中删除一个通用参数并将其替换为Box<dyn Fuel>
,但我想通过动态调度来最小化位置。
但是这个变体也不能编译,因为[编译器]想提前知道
Vehicle
的泛型类型参数。
我认为您在这里混淆了 static 调度和动态调度。 我认为你也混淆了你要求编译器做什么和你期望它做什么。 听起来很明显你想要动态调度,但是你试图使用 generics 来实现它,这是不可能的,因为 generics 是一个纯粹的编译时抽象,并且总是会产生 ZA81259CEF8E959C3297DF1D45E 代码调度。 “泛型”在运行时不存在,也不存在于最终的二进制文件中。 如果您想要“运行时泛型”,那就是特征对象和动态分派的用途。
在 Java 我只会写
List<Vehicle<?>>
。 Rust有类似的吗?
是的,将F: Fuel
通用类型参数替换为dyn Fuel
特征 object。
PS 我显然可以从
Vehicle
中删除一个通用参数并将其替换为Box<dyn Fuel>
,但我想通过动态调度来最小化位置。
但是您只是问如何在 Rust 中执行 Java 等效项,这就是 Java 解决此问题的方式:使用动态调度。 你不能一边吃蛋糕一边吃。 如果您想要 static 调度的速度,这意味着也接受 static 调度的约束。 如果这些约束对您的程序来说过于严格,那么您应该使用特征对象和动态调度。
Rust 的枚举可能是你能得到的最接近你想要的东西。 它们是 generics 和特征对象之间的一个很好的折衷方案,为您提供(几乎)前者的速度,同时为您提供后者的灵活性。 这是重构为使用枚举的示例:
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,
Gas,
}
然后添加 function efficiency
以返回每个燃料变体的效率:
impl Fuel {
fn efficiency(&self) -> f64 {
match self {
Fuel::Diesel => 0.9,
Fuel::Gas => 0.8,
}
}
}
您现在有 2 种相同类型的燃料。
在对车辆执行相同操作后(您也有 2 个变体),您可以将各种组合添加到同一个向量中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.