Vincent P
Vincent P

Reputation: 699

How to return an instance of a trait?

I'm working on a SQL migration tool. Right now I only support Postgresql but i'd like to add Mysql, etc.

I have the following trait that drivers need to implement:

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<()>;
}

I want to make a function get_driver which would have the following conceptual definition fn get_driver(url: &str) -> MigrateResult<Driver>.

Based on a discussion on IRC a month ago, this is apparently impossible to do. My previous best guess fails like so:

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>`

(expected type parameter, found struct drivers::pg::Postgres) [E0308]

Is there any way to work around that?

The full code is available.

Upvotes: 0

Views: 926

Answers (1)

Simon Sapin
Simon Sapin

Reputation: 10180

In this function:

fn get_driver<T: Driver + Sized>(url: &str) -> MigrateResult<T>

T is a type parameter. It is chosen by the caller of the function.

It looks like you want to a return a different type based on the value of url. But Rust is statically-typed: the type of any expression at any point in the code needs to be known at compile-time. (Even generics get specialized to concrete types when they’re used.) The way to deal with this is to use trait objects:

For example, in:

fn get_driver(url: &str) -> MigrateResult<Box<Driver>>

Box<Driver> is a fat pointer made of a pointer to the value and a pointer to the virtual call table for the a concrete type that implements the Driver trait. That vtable contains pointers to the code for each method of the trait.

Read more at http://doc.rust-lang.org/book/trait-objects.html

Upvotes: 3

Related Questions