满口金牙 2024-06-10 13:18 采纳率: 91.1%
浏览 3

rust 生命周期的问题请教 slqx fromRow的问题


写一个基于sqlx组件的 函数
pub async fn aa<'a, T>(
    instance: &'a T,
    table_name: &'a str,
    select_where: &'a str,
) -> Result<&'a T, MyError>
where
    T: Serialize + FromRow<'a, SqliteRow> + WithId + Clone,
{
    let conn = database_conn().await?;
    let select_sql = generate_select_sql(&table_name, &[], &select_where);
    let row = query(&select_sql).fetch_one(&conn).await;
    match row {
        Ok(row_data) => {
            let data = <T as FromRow<'a, SqliteRow>>::from_row(&row_data)?; // 现在 一直报错 row的生命周期
            let update_sql =
            generate_update_sql(&instance, &table_name, &format!("id={}", &data.id()));
            // println!("存在数据:{:?}",a);
            println!("update_sql");
        }
        Err(sqlx::Error::RowNotFound) => {
            println!("");
            let insert_sql = generate_insert_sql(&instance, &table_name);
            let res = execute_sql(vec![insert_sql]).await?;
            // 处理没有找到记录的情况
            println!("不存在数据")
        }
        Err(r) => {
            println!("错误")
        }
    };
    Ok(instance)
}

报错信息如下:

`row_data` does not live long enough
borrowed value does not live long enoughrustcClick for full compiler diagnostic
sql.rs(161, 9): `row_data` dropped here while still borrowed
sql.rs(155, 12): binding `row_data` declared here
sql.rs(143, 17): lifetime `'a` defined here
sql.rs(156, 24): argument requires that `row_data` is borrowed for `'a`
// size = 32 (0x20), align = 0x8
let row_data: SqliteRow
Go to SqliteRow

没有可用的快速修复
  • 写回答

2条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-06-10 13:18
    关注

    引自免费微信小程序:皆我百晓生

    为了解决Rust中生命周期的问题,我们需确保所有借用(borrow)都符合其生命周期约束。在你的函数中,row_data 的生命周期是基于 async 函数内部的执行流,而 datarow_data 的借用则尝试跨越整个函数的生命周期,这是不允许的。

    解决方法在于调整 FromRow 实现以及如何处理获取的数据行。在 SQLx 中,FromRow 结构体通常被用于将数据库查询结果转换为 Rust 类型。为了确保生命周期正确,我们需要让 data 的生命周期与 row_data 相同,但同时也要保证 data 可以在函数返回时仍然有效。

    一个可能的解决方案是使用 Box<T> 或者 Arc<T> 来延长 data 的生命周期,这样 data 就不再受限于 row_data 的生命周期了。然而,考虑到你希望返回一个引用,这可能不是一个直接的解决方案。另一种方式是返回 data 的所有权而非引用,但这可能会改变函数的签名和预期的行为。

    下面是一个修改后的函数实现示例,其中使用 Box<T> 来管理 data 的生命周期,并且函数返回值类型也做了相应的调整:

    use sqlx::{Pool, Sqlite, Error};
    use std::sync::Arc;
    
    pub async fn aa<'a, T>(
        instance: &'a T,
        table_name: &'a str,
        select_where: &'a str,
    ) -> Result<Box<T>, MyError>
    where
        T: Serialize + FromRow<SqliteRow> + WithId + Clone + 'static,
    {
        let conn = database_conn().await?;
        let select_sql = generate_select_sql(table_name, &[], select_where);
        let row_data = query(&select_sql).fetch_one(&conn).await?;
        
        let data = Box::new(<T as FromRow<SqliteRow>>::from_row(&row_data)?);
        let update_sql = generate_update_sql(&*data, table_name, &format!("id={}", data.id()));
        
        Ok(data)
    }
    

    这里的关键变化包括:

    • 返回类型从 Result<&'a T, MyError> 改为 Result<Box<T>, MyError>
    • 使用 Box<T> 包装 data,确保 data 的生命周期不受限于 row_data
    • 移除了泛型参数 'a 和对 'a 的约束,因为现在我们不依赖于任何外部生命周期。
    • 在调用 generate_update_sql 之前,使用 &*data 来访问 data 内部的内容。

    这样修改后,data 的生命周期将不再受限于 row_data,并且函数可以安全地返回 data 的所有权。

    如果你确实需要返回一个引用而不是所有权,你可能需要重新考虑你的设计,或者使用更复杂的内存管理和生命周期管理策略,比如 RcArc 或者 RefCell 等特性,但这通常会增加代码的复杂度和维护难度。在这个场景下,返回所有权是一个更为简洁和安全的选择。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 6月10日

悬赏问题

  • ¥15 两台交换机分别是trunk接口和access接口为何无法通信,通信过程是如何?
  • ¥15 C语言使用vscode编码错误
  • ¥15 用KSV5转成本时,如何不生成那笔中间凭证
  • ¥20 ensp怎么配置让PC1和PC2通讯上
  • ¥50 有没有适合匹配类似图中的运动规律的图像处理算法
  • ¥15 dnat基础问题,本机发出,别人返回的包,不能命中
  • ¥15 请各位帮我看看是哪里出了问题
  • ¥15 vs2019的js智能提示
  • ¥15 关于#开发语言#的问题:FDTD建模问题图中代码没有报错,但是模型却变透明了
  • ¥15 uniapp的h5项目写一个抽奖动画