我正在寻找关于如何解决Rust 问题的理解.在so,OFC上有很多类似的问题,但没有一个看起来完全相同--所有其他问题似乎都是关于 struct 或‘静态的,我的是关于我从外部库中使用的一个特性,具有开放的生命周期.

我使用tokio_postgres来查询数据库中的行,就像一个人做的那样.我正在努力简化我经常做的一些操作.从查询中获取一组UUID很容易:

pub fn rows_as_first(rows: Vec<Row>) -> Vec<Uuid> {
    rows.into_iter().map(|row| row.get(0)).collect()
}

这很管用.但是,当我try 将其泛化时(例如,收集字符串或其他东西):

pub fn rows_as_first_generic<'a, T: FromSql<'a>>(rows: Vec<Row>) -> Vec<T> {
    rows.into_iter().map(|row| row.get(0)).collect()
}

我收到一个错误:

error[E0597]: `row` does not live long enough
  --> backend-axum/src/queries.rs:64:32
   |
63 | pub fn rows_as_first_generic<'a, T: FromSql<'a>>(rows: Vec<Row>) -> Vec<T> {
   |                              -- lifetime `'a` defined here
64 |     rows.into_iter().map(|row| row.get(0)).collect()
   |                           ---  ^^^-------
   |                           |    |        |
   |                           |    |        `row` dropped here while still borrowed
   |                           |    borrowed value does not live long enough
   |                           |    argument requires that `row` is borrowed for `'a`
   |                           binding `row` declared here

现在,我绝对理解row只在关闭的时间内存活,这完全有道理.我不明白的是:

  1. 这个函数的UUID版本有什么不同,它没有抱怨吗?我认为有一些特性使它神奇地工作,我想知道a)它是什么,以及b)当try 在Ruust中重构这样的代码时,将来如何发现这些信息.(这不是我第一次在重构时遇到类似的问题.)

  2. 如果a)不是引用,因为我拥有它,b)当我根本不想要引用时,我也想拥有最终结果,那么我应该如何为引用添加生存期呢?

我对T: FromSql<'a>持怀疑态度--也许它需要进一步澄清.get(0)调用需要它,根据定义,我返回的是来自SQL查询的一些值.但我不想要参考,我想要拥有最终的结果.我很高兴做clone()米来实现这一点,只是看起来这不是问题所在.(当然,我试着添加了clone().)

因此,不知何故,我应该在行上有一个终生说明符,但Tokio_postgres的工作方式是:

client.query(&stmt, params).await?

返回Vec<Row>,但不包括生存期,因为它是拥有的.所以...我该怎么做?UUID示例是如何工作的?我确信我在这里遗漏了一些基本的和明显的东西,所以...抱歉的.

也谢谢你.

推荐答案

很棒的问题!让我先试着回答你的第二个问题.你说得对,它的核心是T: FromSql<'a>.此签名:

pub fn rows_as_first_generic<'a, T: FromSql<'a>>

'a作为一个input的生命周期,这意味着签名说:"对于任何生命周期'a Select the callerrows_as_first_genericT必须是可创建的从一个postgres值,生活为'a".这不是你想要的:你想要一个T,它可以从一个postgres值中创建,该值的生存期是rows_as_first_generic Select 的(不是它的调用者)--即你在函数体中提到的get调用的生存期.你用rust写这个的方式是:

pub fn rows_as_first_generic<T: for<'a> FromSql<'a>>

这说明:T必须是从一个具有any生命周期的postgres值创建的.(即T必须在任何生命周期'a内实现FromSql<'a>).因此,特别是,它可以从postgres值中创建,该值的生命周期 与行的生命周期 一样长.

对于您的第一个问题,为什么Uuid工作以及如何发现差异:它对Uuid工作的原因是Uuid确实在任何生存期内实现了FromSql(如您所见in the tokio_postgres docs).

我不确定我有什么建议,除了练习这些模式和建立关于什么错误建议什么解决方案的直觉.在这种情况下,如果一个trait绑定需要在某个输入生命周期内borrow 一些临时值(这就是你上面得到的错误),有时是因为你真的想要一个HRTB,就像这个例子一样.另一种方法是采用&'a Vec<Row>或类似的值,在这种情况下,您可以使用输入生存期.也就是说,这也可以工作:

pub fn rows_as_first_generic_input<'a, T: FromSql<'a>>(rows: &'a Vec<Row>) -> Vec<T>

因为现在调用者保证您可以在T需要它的时间长度内保持Row(而不是原始代码短暂的临时生命周期).希望能对大家有所帮助!

Rust相关问答推荐

为什么父作用域中的变量超出了子作用域

基于对vec值的引用从该值中删除该值

rust 蚀将动力特性浇到混凝土 struct 上是行不通的

如何从polars DataFrame中获取一个列作为Option String?<>

在Rust中宏的表达式中提取对象

如何实现泛型枚举的`Serde::Desialize`特性

在UdpSocket上使用sendto时的隐式套接字绑定

交换引用时的生命周期

Rust 的多态现象.AsRef与Derf

为什么Option类型try块需要类型注释?

在 Rust 中,在需要引用 self 的 struct 体方法中使用闭包作为 while 循环条件

将泛型中的 Box 转换为 rust 中的 Box

rust 中不同类型的工厂函数

如何在 use_effect_with_deps 中设置监听器内的状态?

Rust 中函数的类型同义词

使用部分键从 Hashmap 中检索值

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?

为什么 Rust 标准库同时为 Thing 和 &Thing 实现特征?

为什么在使用 self 时会消耗 struct 而在解构时不会?

如何阅读 HttpRequest 主体