使用Diesel的泛型函数引发编译溢出错误求助
解决Diesel泛型函数的递归求值溢出问题
你遇到的递归求值溢出问题,本质是Diesel的泛型trait关联类型之间存在复杂的递归依赖,编译器无法在默认(甚至调高后的)递归限制内完成解析。单纯调高递归限制不是根本解法,我们需要调整泛型约束的写法,同时修正代码里的几个隐藏问题。
问题分析
- 泛型约束过于间接:你通过
Table和FindDsl间接约束查询类型,导致编译器需要递归解析多层关联类型,最终触发求值溢出。 - 连接管理不当:
get_connection()在函数内每次调用都会新建数据库连接,既低效也不必要。 - 查询方法误用:
load()方法返回的是Vec<Model>,但你试图赋值给Model类型变量,这会导致后续的类型错误(当前被递归错误掩盖了)。
修正后的代码
调整get_row函数的设计,让它直接接受已构建好的查询,并复用数据库连接:
#[macro_use] extern crate diesel; extern crate dotenv; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; table! { table1 (id) { id -> Int4, value -> Text, } } table! { table2 (id) { id -> Int4, value -> Text, } } #[derive(Identifiable, Queryable, Serialize)] #[table_name = "table1"] struct Model1 { pub id: i32, pub value: String, } #[derive(Identifiable, Queryable, Serialize)] #[table_name = "table2"] struct Model2 { pub id: i32, pub value: String, } use dotenv::dotenv; use std::env; fn get_connection() -> PgConnection { dotenv().ok(); let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); PgConnection::establish(&database_url).expect("Database connection failed") } use diesel::QueryDsl; use diesel::pg::PgConnection; use diesel::RunQueryDsl; // 引入该trait以使用get_result方法 use diesel::result::Error; use serde::Serialize; use serde_json::to_string; // 简化泛型约束,直接接受实现LoadQuery的查询类型 fn get_row<Model, Q>(query: Q, conn: &PgConnection) -> Result<String, Error> where Q: LoadQuery<PgConnection, Model>, Model: Serialize, { // 使用get_result获取单个行,替代返回Vec的load方法 let result: Model = query.get_result(conn)?; Ok(to_string(&result)?) } fn main() { let conn = get_connection(); // 复用单个数据库连接 let row1 = get_row(table1::table.find(1), &conn); let row2 = get_row(table2::table.find(1), &conn); // 示例:处理查询结果 match row1 { Ok(json) => println!("Row1: {}", json), Err(e) => eprintln!("Error fetching row1: {}", e), } match row2 { Ok(json) => println!("Row2: {}", json), Err(e) => eprintln!("Error fetching row2: {}", e), } }
关键改动说明
- 简化泛型约束:直接让函数接受实现
LoadQuery<PgConnection, Model>的查询类型Q,避免了间接约束带来的递归解析问题,让编译器能直接识别类型依赖。 - 复用数据库连接:在
main中创建一次连接并传入函数,提升性能,避免重复建立连接的开销。 - 替换查询方法:用
get_result()替代load(),因为find(id)查询的是单个行,get_result()会直接返回单个Model实例,符合你的业务需求。
Cargo.toml 优化建议
建议指定依赖的具体版本(避免使用*),确保构建的稳定性:
[package] name = "question" version = "0.1.0" [dependencies] diesel = { version = "1.4.8", features = ["postgres"] } dotenv = "0.15.0" serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.91"
这样调整后,编译器就能正确解析泛型约束,不会再出现递归求值溢出的问题,同时也修正了潜在的类型错误。
内容的提问来源于stack exchange,提问作者Luuk Wester
相关产品推荐
相关产品推荐

