Rust中使用Tiberius查询MS SQL返回Vec的生命周期借用错误
解决Tiberius读取SQL数据返回Vec<结构体>的借用错误
错误原因
错误提示cannot return value referencing local variable 'row'的核心问题是:Fornitori结构体中的&str字段引用的是函数内局部变量row中Row对象的数据。函数执行完毕后row会被销毁,对应的引用会变成悬垂引用,Rust的所有权机制会直接阻断这种不安全操作。
解决方案
将结构体中的引用类型替换为拥有所有权的String类型,让结构体持有自己的数据,不再依赖局部变量的生命周期。
修改后的结构体定义
#[derive(Clone, Debug)] pub struct Fornitori { pub f_id: Option<i32>, pub fornitore: Option<String>, pub tipo_pagamento: Option<String>, }
修改后的函数代码
use tiberius::{Client, Config, AuthMethod, Query, Row}; use tokio::net::TcpStream; use tokio_util::compat::TokioAsyncWriteCompatExt; pub mod structures; use structures::*; #[tokio::main] pub async fn get_fornitori() -> anyhow::Result<Vec<Fornitori>> { let mut config = Config::new(); config.host("foo"); config.port(1433); config.authentication(AuthMethod::sql_server("foo", "bar")); config.database("foo"); config.trust_cert(); // 生产环境不建议这么做 let tcp = TcpStream::connect(config.get_addr()).await?; tcp.set_nodelay(true)?; let mut client = Client::connect(config, tcp.compat_write()).await?; let params = vec![String::from("*")]; let mut select = Query::new("SELECT TOP 3 * FROM foo"); for param in params.into_iter() { select.bind(param); } let mut _res = select.query(&mut client).await?; let row: Vec<Vec<Row>> = _res.into_results().await?; let mut result_vec: Vec<Fornitori> = vec![]; for i in &row[0] { let id_forn: Option<i32> = i.get(0); // 将查询得到的&str转换为String,通过map处理Option类型 let nome_forn: Option<String> = i.get::<&str>(1).map(|s| s.to_string()); let pagamento_forn: Option<String> = i.get::<&str>(4).map(|s| s.to_string()); let forn = Fornitori { f_id: id_forn, fornitore: nome_forn, tipo_pagamento: pagamento_forn, }; result_vec.push(forn); } println!("rvec: {:#?}", result_vec); Ok(result_vec) }
说明
修改后,结构体Fornitori拥有自己的字符串数据,不再依赖函数内局部变量的生命周期,函数返回时就不会触发借用检查错误。
内容的提问来源于stack exchange,提问作者GranBoh
相关产品推荐
相关产品推荐

