简体   繁体   English

实例化由特征参数化的结构

[英]Instantiating a struct parameterized by a trait

I'm building a webapp in Rust and trying to implement basic Rails-style database migrations for managing my database. 我正在Rust中构建一个webapp,并尝试实现基本的Rails风格的数据库迁移来管理我的数据库。 In my code, Migration is a trait with up and down methods to apply and roll back the migration. 在我的代码, Migration是与性状updown的方法来应用和回滚迁移。 Each individual database migration is a struct that implements the Migration trait. 每个单独的数据库迁移都是实现迁移特征的结构。 To keep track of database migrations in the correct order, I built a MigrationIndex class. 为了以正确的顺序跟踪数据库迁移,我构建了一个MigrationIndex类。

struct MigrationIndex<T> {
    migrations: Vec<Box<T>>
}
impl <T: Migration> MigrationIndex<T> {
    // methods for managing the migrations...
}

impl <T: Migration> Default for MigrationIndex<T> {
    pub fn default() -> MigrationIndex<T> {
        MigrationIndex {
            migrations: vec![]
        }
    }
}

So I go to use my class: 所以我去上课:

let migrations: MigrationIndex = Default::default();

But the compiler errors on this line with wrong number of type arguments: expected 1, found 0 . 但是这行上的编译错误wrong number of type arguments: expected 1, found 0 So I tried to add the missing trait parameter: 所以我尝试添加缺少的特征参数:

let migrations: MigrationIndex<Migration> = Default::default();

But on that line the compiler interprets Migration as a type, not a trait, and again fails to compile. 但是在那一行上,编译器将Migration解释为一种类型,而不是一种特征,并且再次无法编译。 At a guess I tried: 猜测我试过了:

let migrations: MigrationIndex<T: Migration> = Default::default();

but that ends up being a syntax error. 但最终会出现语法错误。 Now I'm stumped. 现在我很难过。 If a type is parameterized by a trait, how do I specify that trait when I instantiate it? 如果某个类型由特征参数化,那么在实例化时如何指定该特征?

When you specify a value for a generic type parameter, it has to be a concrete type, not a trait: 为泛型类型参数指定值时,它必须是具体类型,而不是特征:

trait Migration {}

struct Foo;
impl Migration for Foo {}

fn main() {
    let migrations: MigrationIndex<Foo> = Default::default();
}

When you use a generic, the generic argument needs to be of a single concrete type. 使用泛型时,泛型参数必须是单个具体类型。 This would cause all objects in the migrations Vec to be of the same type. 这将导致迁移Vec中的所有对象具有相同的类型。 From your description it does not sound like that's what you want. 根据你的描述,这听起来并不像你想要的那样。 You want a Vec of different types that implement the same trait. 您想要一个实现相同特征的不同类型的Vec This does not require generics: 这不需要泛型:

#[derive(Default)]
struct MigrationIndex {
    migrations: Vec<Box<Migration>>
}
impl MigrationIndex {
    // methods for managing the migrations...
}

I also took the liberty of replacing your manual Default impl with the equivalent automatically generated one through the derive attribute. 我还冒昧地通过derive属性用等效的自动生成的替换你的手动Default impl。

In fact, in your previous implementation, the Box was entirely unnecessary. 实际上,在您之前的实现中, Box完全没有必要。 If you have a concrete type, you can create a Vec of elements of that type directly. 如果您具有具体类型,则可以直接创建该类型的Vec元素。 Only when you want to put in different types implementing the same trait do you need the Box , because these types might have different sizes. 只有当你想要放入实现相同特征的不同类型时才需要Box ,因为这些类型可能有不同的大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM