我在Rust中构建一个webapp并尝试实现基本的Rails风格的数据库迁移来管理我的数据库。在我的代码中,Migration
是一种使用up
和down
方法应用和回滚迁移的特征。每个单独的数据库迁移都是实现迁移特征的结构。为了按正确的顺序跟踪数据库迁移,我构建了一个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![]
}
}
}
所以我去上课:
let migrations: MigrationIndex = Default::default();
但编译器错误在wrong number of type arguments: expected 1, found 0
这一行。所以我尝试添加缺少的特征参数:
let migrations: MigrationIndex<Migration> = Default::default();
但是在那一行上,编译器将Migration解释为一种类型,而不是一种特征,并且再次无法编译。猜测我试过了:
let migrations: MigrationIndex<T: Migration> = Default::default();
但最终会出现语法错误。现在我很难过。如果某个类型是由特征参数化的,那么在实例化它时如何指定该特征呢?
答案 0 :(得分:3)
为泛型类型参数指定值时,它必须是具体类型,而不是特征:
trait Migration {}
struct Foo;
impl Migration for Foo {}
fn main() {
let migrations: MigrationIndex<Foo> = Default::default();
}
答案 1 :(得分:3)
使用泛型时,泛型参数必须是单一的具体类型。这将导致迁移Vec
中的所有对象属于同一类型。根据你的描述,这听起来并不像你想要的那样。您需要实现相同特征的Vec
个不同类型。这不需要泛型:
#[derive(Default)]
struct MigrationIndex {
migrations: Vec<Box<Migration>>
}
impl MigrationIndex {
// methods for managing the migrations...
}
我还冒昧地用Default
属性替换您的手册derive
impl与等效的自动生成的。{/ p>
事实上,在您之前的实施中,Box
完全没必要。如果您具有具体类型,则可以直接创建该类型的Vec
个元素。只有当您想要实现相同特征的不同类型时才需要Box
,因为这些类型可能有不同的大小。