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


    关注 码龄 粉丝数 原力等级 -- 被采纳 被点赞 采纳率 满口金牙 2024-06-10 13:18 采纳率: 91.1% 浏览 2 首页/ 编程语言 / rust 生命周期的问题请教 slqx fromRow的问题 rust有问必答 写一个基于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 = >::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 没有可用的快速修复 展开全部 收起 写回答 好问题 0 提建议 追加酬金 关注问题 微信扫一扫 点击复制链接 分享 邀请回答 编辑 收藏 删除 结题 收藏 举报 追加酬金 (90%的用户在追加酬金后获得了解决方案) 当前问题酬金 ¥ 0 (可追加 ¥500) ¥ 15¥ 20¥ 50¥ 100¥ 200 支付方式 扫码支付 二维码出错 点击刷新 支付金额 15 元 提供问题酬金的用户不参与问题酬金结算和分配 支付即为同意 《付费问题酬金结算规则》 结题 再想想 删除 再等等

    2条回答 默认 最新

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

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

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

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

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

      下面是一个修改后的函数实现示例,其中使用 Box 来管理 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, MyError>
      where
          T: Serialize + FromRow + 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(>::from_row(&row_data)?);
          let update_sql = generate_update_sql(&*data, table_name, &format!("id={}", data.id()));
          
          Ok(data)
      }
      

      这里的关键变化包括:

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

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

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

      展开全部

      评论 编辑记录
    • 阿里嘎多学长 2024-06-10 13:18
      关注

      以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


      在 Rust 中,生命周期问题通常与借用的有效期有关。在您提供的代码中,row_data 是从数据库查询得到的,它的生命周期与 async 块的执行期间绑定。但是,您试图将 row_data 转换为类型 T,并且希望这个转换后的数据具有与 instance 相同的生命周期 'a。这通常是不可能的,因为 row_data 的生命周期仅限于 async 块。

      要解决这个问题,我们可以考虑以下几个方向:

      1. 使用更短的生命周期:如果 T 的实现不需要 row_data 的整个生命周期,您可以尝试使用更短的生命周期。例如,您可以在 FromRow trait 中使用 'static 生命周期,这意味着数据是静态的或者已经拥有足够的生命周期。

      2. 避免在 Result 中返回引用:在您的函数签名中,您返回的是 Result<&'a T, MyError>。如果 T 是从 row_data 转换来的,那么这个引用将无法满足 'a 生命周期的要求。您可能需要返回一个 BoxRc 来拥有数据,而不是借用它。

      3. 使用 PinProject 模式:如果 T 是一个更复杂的类型,您可能需要使用 Pin 来确保数据在异步操作中不会被移动,然后使用 Project 模式来安全地访问内部数据。

      4. 修改 FromRow trait 的实现:可能需要修改 FromRow trait 的实现,以确保它不违反生命周期规则。

      下面是一个修改后的示例,使用 Box 来解决问题:

      use sqlx::FromRow;
      
      pub async fn aa(
          instance: T,
          table_name: &str,
          select_where: &str,
      ) -> Result, MyError>
      where
          T: Serialize + FromRow<'static, 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;
          let data = match row {
              Ok(row_data) => T::from_row(&row_data).map_err(|e| e.into()), // 使用 'static 生命周期
              Err(sqlx::Error::RowNotFound) => {
                  let insert_sql = generate_insert_sql(&instance, &table_name);
                  let _res = execute_sql(vec![insert_sql]).await?;
                  return Err(MyError::NotFound); // 或其他适当的错误处理
              }
              Err(e) => return Err(e.into()),
          }?;
      
          let update_sql = generate_update_sql(&instance, &table_name, &format!("id={}", data.id()));
          println!("update_sql");
      
          Ok(Box::new(data))
      }
      

      请注意,这里假设 FromRow 能够使用 'static 生命周期,这可能需要您调整 FromRow 的实现。此外,返回值现在是 Box,这意味着函数现在拥有数据而不是借用它。

      关于 Rust 生命周期的更多信息,您可以查看 Rust 官方文档:

      关于 sqlx 库的使用,您可以查看它的官方文档:

      展开全部

      评论 编辑记录
    编辑
    预览

    报告相同问题?

  • 相关阅读:
    Android 天气APP(三十六)运行到本地AS、更新项目版本依赖、去掉ButterKnife
    .NET混合开发解决方案5 WebView2运行时与分发应用
    yum安装jdk环境
    Reading Notes For Introduction To Linux
    Java#7(this关键字和构造方法)
    前端进击笔记第八节 一个网络请求是怎么进行的?
    MS COCO数据集的评价标准以及不同指标的选择推荐(AP、mAP、MS COCO、AR、@、0.5、0.75、1、目标检测、评价指标)
    什么是尾调用优化和尾递归?
    Vue(七)——vuex(vuex基础,使用,state,getters,mutations,actions基本概念与使用以及基本实现案例)
    客服支持Chatbot提供即时回答,改善用户体验
  • 原文地址:https://ask.csdn.net/questions/8116444