使用特征作为数据库实体的接口

Use trait as interface for database entity

我正在尝试创建一个 Entity 接口,用于将数据库结果动态映射到 Rust 结构中:

pub trait Entity {
    fn map(&self, Result<QueryResult>) -> Self;
}

pub struct DbQuery<T> {
    pub sql: String,
    pub params: Vec<Value>,
    pub limit: i32,
    pub paged: Option<Pagination>,
    pub entity: T,
}

pub struct Settings {
    pub name: String,
    pub value: Option<String>,
}

impl Entity for Settings {
    fn map(&self, result: Result<QueryResult>) -> Settings {
        // ...
        Settings {
            name: "hello".to_string(),
            value: None,
        }
    }
}

impl DbMapper {
    // ...

    pub fn find<T>(&self, query: DbQuery<T>) -> Option<Vec<T>> {
        println!("query find SQL: {}", query.sql);
        let mut stmt = &self.pool.prepare(query.sql).unwrap();
        let ret = Vec::new();
        for row in stmt.execute(query.params).unwrap() {
            ret.push(query.entity.map(row.unwrap()));

        }

        Some(ret)
    }
}

但是我得到一个错误:

error: no method named map found for type T in the current scope
ret.push(query.entity.map(row.unwrap())); |
note: the method map exists but the following trait bounds were not satisfied: T : std::iter::Iterator = help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item map, perhaps you need to implement one of them: = help: candidate #1: models::holders::database::Entity = help: candidate #2: std::iter::Iterator

Here is a version of your code that runs on the playground 并重复您的问题:

pub struct QueryResult;
pub struct Value;
pub struct Pagination;
pub struct DbMapper;

pub trait Entity {
    fn map(&self, Result<QueryResult, ()>) -> Self;
}

pub struct DbQuery<T> {
    pub sql: String,
    pub params: Vec<Value>,
    pub limit: i32,
    pub paged: Option<Pagination>,
    pub entity: T,
}

pub struct Settings {
    pub name: String,
    pub value: Option<String>,
}

impl Entity for Settings {
    fn map(&self, result: Result<QueryResult, ()>) -> Settings {
        // ...
        Settings {
            name: "hello".to_string(),
            value: None,
        }
    }
}

impl DbMapper {
    // ...

    pub fn find<T>(&self, query: DbQuery<T>) -> Option<Vec<T>> {
        println!("query find SQL: {}", query.sql);

        // ########## attempt to call map()
        let _ = query.entity.map(Ok(QueryResult {}));

        let ret = Vec::new();
        Some(ret)

    }
}

fn main() {}

问题是 find 方法的 DbQuery<T> 参数中的 T 不知道 TEntity 类型。所以我们需要告诉它:

pub fn find<T>(&self, query: DbQuery<T>) -> Option<Vec<T>>
    where T: Entity
{
    // ... code here ...
}

This now compiles and runs.

编译器现在知道 T 是某个描述的 Entity,它可以调用它的 map 方法。