我正在研究a SQL migration tool。 现在我只支持Postgresql,但我想添加Mysql等。
我有以下特征,司机需要实施:
pub trait Driver {
fn ensure_migration_table_exists(&self);
fn remove_migration_table(&self);
fn get_current_number(&self) -> i32;
fn set_current_number(&self, number: i32);
fn migrate(&self, migration: String, number: i32) -> MigrateResult<()>;
}
我想创建一个函数get_driver
,它具有以下概念定义fn get_driver(url: &str) -> MigrateResult<Driver>
。
根据一个月前对IRC的讨论,这显然是不可能的。我之前的最佳猜测失败了:
fn get_driver<T: Driver + Sized>(url: &str) -> MigrateResult<T>
expected `core::result::Result<T, errors::MigrateError>`,
found `core::result::Result<drivers::pg::Postgres, errors::MigrateError>`
(预期的类型参数,
找到了结构drivers::pg::Postgres
)[E0308]
有什么方法可以解决这个问题吗?
答案 0 :(得分:3)
在此功能中:
fn get_driver<T: Driver + Sized>(url: &str) -> MigrateResult<T>
T
是类型参数。它由函数的调用者选择。
看起来您希望根据url
的值返回其他类型。但Rust是静态类型的:代码中任何一点的任何表达式的类型都需要在编译时知道。 (即使泛型在使用时也会专门针对具体类型。)处理这个问题的方法是使用特征对象:
例如,在:
fn get_driver(url: &str) -> MigrateResult<Box<Driver>>
Box<Driver>
是一个胖指针,由一个指向该值的指针和一个指向虚拟调用表的指针组成,用于实现{的具体类型{1}}特质。该vtable包含指向每个特征方法的代码的指针。