当前位置: 首页 > 知识库问答 >
问题:

如何在 Rust 中创建对通用特征对象的引用 Vec?[重复]

梁盛
2023-03-14

我是Rust的新手。我的背景是Java。我正在努力解决以下问题。

  1. 我有一个特性燃料,它是为struct-Dieselstruct-Gas
  2. 我还有一个特征车辆,带有燃油通用类型参数。车辆是为<代码>结构车实现的

最后,我想将对可能的异构特征对象的引用放入一个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的东西

整个例子都可以在操场上看到。

附言:我显然可以从车辆中删除通用参数并将其替换为Box


共有2个答案

林弘文
2023-03-14
匿名用户

不可能将不同的类型放在同一个向量中。但是,使用枚举,您可以获得所需的功能,而无需不同的类型。

因为您有两种不同的燃料,它们的枚举将如下所示:

pub enum Fuel {
    Diesel,
    Gas,
}

然后添加一个函数< code>efficiency来返回各种燃料的效率:

impl Fuel {
    fn efficiency(&self) -> f64 {
        match self {
            Fuel::Diesel => 0.9,
            Fuel::Gas => 0.8,
        }
    }
}

您现在有两种类型相同的燃油。

对车辆进行同样的操作后(你也有2个车辆的变体),你可以将不同的组合添加到同一个向量中。

这是一个完整的例子。

你可以在这里阅读枚举。

徐智渊
2023-03-14

但是这个变体也没有编译,因为[编译器]想事先知道车辆的泛型类型参数。

我认为你在这里混淆了静态调度和动态调度。我认为你也混淆了你要求编译器做什么和你期望它做什么。很明显,这听起来像是你想要动态调度,但你正试图使用泛型来实现它,这是不可能的,因为泛型是一种纯粹的编译时抽象,并且总是会产生静态调度代码。“泛型”在运行时不存在,也不存在于最终的二进制文件中。如果你想要“运行时泛型”,这就是特征对象和动态调度的用途。

在Java中,我只需编写<code>列表

是,将F:Fuel泛型类型参数替换为dyn-Fueltrait对象。

附言:我显然可以从车辆中删除通用参数并将其替换为Box

但您刚刚问了如何在Rust中实现Java等价物,Java就是这样解决这个问题的:通过使用动态调度。你不能既有蛋糕又吃。如果您想要静态调度的速度,这意味着也要接受静态调度的约束。如果这些约束对于您的程序来说太严格,那么您应该使用trait对象和动态调度。

Rust的枚举可能是最接近您想要的。它们是泛型和特质对象之间的一个很好的折衷方案,让你(几乎)拥有前者的速度,同时也让你拥有后者的灵活性。以下是您重构使用枚举的示例

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
    ];
}

游乐场

 类似资料:
  • 我正在Rust中编写一个带有控制台提示界面的进程内存扫描器。 我需要扫描仪类型,如winapi扫描仪或ring0驱动程序扫描仪,所以我试图实现多态性。 目前我有以下结构: 将来,除了 之外,我还会有更多扫描仪类型,因此,如果我理解正确,我应该使用特征引用 (

  • 我正在尝试创建一个特征对象的向量,但我得到了类型不匹配。我还尝试使用代替for循环,但遇到了同样的问题。这是我真实代码的最小版本,我意识到这个例子不需要使用特征对象,但我的真实代码需要,因为列表中除了之外还有其他类型,它们也实现了。如何使用正确的类型创建以便将其传递给?

  • (这是我第二次尝试追踪我的确切问题。查看编辑历史记录) 我有一个简单的通用特性和两种不同的实现: 我现在想要一个包含两个实现元素的向量。正如我在这里学到的,我做: 但是编译器不同意: 一方面,这是有道理的。另一方面,我应该为写什么?我希望它是通用的,所以我不能简单地在那里放或。我可以做

  • 我的情况是,我希望一些对象实现一个特征,比如说“基本”,而其他一些对象将实现一个特征“超级”。Super trait还必须是< code>T : Base的泛型,这样我就可以根据它所专用的Base自动实现Super的各个部分。现在,这似乎可以很好地处理下面的小例子 我的问题与我的下一个要求有关,那就是我希望能够存储实现Super的对象向量,而不管它专门用于哪个Base。我的想法是创建一个涵盖所有超

  • 我试图获得对创建java的GoogleMap对象的引用,但我不知道如何获得这个引用。

  • 关于一个语言被称为面向对象所需的功能,在编程社区内并未达成一致意见。Rust 被很多不同的编程范式影响,包括面向对象编程;比如第十三章提到了来自函数式编程的特性。面向对象编程语言所共享的一些特性往往是对象、封装和继承。让我们看一下这每一个概念的含义以及 Rust 是否支持他们。In my view the Gang of Four is the best book ever written on