Infer типы для конструктора типов - PullRequest
0 голосов
/ 06 мая 2019

Это может показаться конкретным вопросом, но я постараюсь обобщить его как можно больше. Не стесняйтесь редактировать заголовок, так как я новичок в Rust и не знаю, как его кратко сформулировать.

То, что я хочу сделать, лучше всего объяснить на примере.

Я использую дизель и сгенерировал schema.rs, который определяет таблицы Cats и Dogs (с макросом table!).

Теперь я написал get_all функции для Cat и Dog (2 структуры, которые я реализовал)

pub fn get_all_cats(connection: &PgConnection) -> Vec<Cat> {
    Cats
        .load::<Cat>(connection)
        .expect("Error")
}

pub fn get_all_dogs(connection: &PgConnection) -> Vec<Dog> {
    Dogs
        .load::<Dog>(connection)
        .expect("Error")
}

Но поскольку они в основном делают то же самое, я бы хотел обобщить их методом get_all<T>.

Я думал о создании черты:

trait GetAll<T=Self> {
   fn get_all(conn: &PgConnection) -> Vec<T> {
      Resource.load::<T>(conn)
   }
}

И, конечно, мне нужно определить Resource сейчас, или Cats или Dogs. Поэтому я хотел сделать обходной путь и определить метод get_resource, который я могу переопределить в Cat и Dog, чтобы получить их уважаемый ресурс. Это типа diesel::query_dsl::RunQueryDsl<Conn>.

Проблема в том, что я понятия не имею, какие ограничения типа * должны реализовывать Conn (а затем Аргументы Типа этого Типа и т. Д.), И я думаю, что должен быть более простой способ обратного инжиниринга всего Тип-Цепочка от дизеля.

trait GetAll<T=Self> {
   fn get_resource() -> diesel::query_dsl::RunQueryDsl;

   fn get_all(conn: &PgConnection) -> Vec<T> {
      get_resource().load::<T>(conn)
   }
}

Это не с expected 1 type argument

Есть ли "исправление" для моего подхода (например, компилятор автоматически определяет тип) или дизайн нарушен? Если последнее так, как я могу обобщить метод get_all?

PS: То же самое касается черты Queryable, которая должна быть ограничением для T, но снова требует 2 параметра типа.

1 Ответ

1 голос
/ 06 мая 2019

Похоже, вам нужен связанный тип для вашей черты.Это позволяет вам выразить тот факт, что структура данных имеет уникальный тип ресурса, связанный с ним.

trait GetAll {
    type Resource; 
    fn get_all(conn: &PgConnection) -> Vec<Self> {
        Self::Resource::load::<Self>(conn)
    }
}

impl GetAll for Dog {
    type Resource = Dogs;
}

impl GetAll for Cat {
    type Resource = Cats;
}

, который вы должны использовать следующим образом:

let dogs = Dog::get_all(&conn);
let cats = Cat::get_all(&conn);
...