Rust Diesel中如何不绑定具体后端为带泛型的结构体实现Trait
解决方案
完全可以不绑定具体数据库后端实现该trait,你遇到的错误是由两个问题共同导致的:
- 错误中出现
Pg的原因:diesel 会根据 Cargo.toml 中启用的数据库后端 feature 生成默认的 schema 约束,你开启了 postgres feature,所以编译器推导时会默认尝试匹配 Pg 后端,和你声明的泛型参数产生冲突。 - 你的泛型约束不足:仅声明了后端支持 Bool 类型的 SQL 表达,缺少了 Rust 类型和 SQL 类型的序列化/反序列化约束。
修正后的代码
use diesel::select; use crate::authenticator::AuthDB; use crate::diesel::dsl::exists; use crate::diesel::prelude::*; use crate::schema::users; // 可以移除多余的泛型参数B,直接通过Connection的关联类型Backend获取后端类型 pub struct DB<C> where C: diesel::Connection, { conn: C, } impl<C> AuthDB for DB<C> where C: diesel::Connection, // 约束1:后端支持Bool、Text两种SQL类型 C::Backend: diesel::sql_types::HasSqlType<diesel::sql_types::Bool> + diesel::sql_types::HasSqlType<diesel::sql_types::Text>, // 约束2:Rust bool类型可以从后端的Bool SQL类型反序列化 bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, C::Backend>, // 约束3:Rust String类型可以序列化为后端的Text SQL类型 String: diesel::serialize::ToSql<diesel::sql_types::Text, C::Backend>, { fn exists_by_id_and_password( &self, id: String, password: String, ) -> Result<bool, crate::error::Error> { Ok(select(exists( users::dsl::users.filter( users::dsl::username .eq(id) .and(users::dsl::password.eq(password)), ), )) .get_result::<bool>(&self.conn)?) } }
补充说明
只要你不在表结构中使用某款数据库特有的字段类型,该实现可以兼容所有 diesel 支持的数据库后端,后续切换后端只需要修改 Cargo.toml 中的 feature 配置、实例化DB时传入对应后端的连接实例即可,不需要修改业务逻辑代码。
内容的提问来源于stack exchange,提问作者wangjun
相关产品推荐
相关产品推荐

