在迭代中使用 Rust 中的通用 From-Trait

Use generic From-Trait in Rust in Iteration

我尝试编写一个简单的 postgres(=0.19.0) 查询函数,它将 Row 转换为我需要的 Type。

当我使用非通用类型时,它可以正常工作而不会出现编译错误:

#[derive(Clone, Debug)]
struct Entry {
  id: u32,
  value: u32,
}

impl<'a> From<&'a Row> for Entry {
  fn from(row: &'a Row) -> Self {
    Entry {
      id: row.get(0),
      value: row.get(1),
    }
  }
}

fn query<'a, T: FromSql<'a>>(client: &mut Client, query_str: &str, params: &[&(dyn ToSql + Sync)]) -> Vec<Entry>  {
  client.query(query_str, params)
    .map(|rows| {
      rows
        .iter()
        .map(|r| {
          Entry::from(r)
        })
        .collect()
    })
    .unwrap_or(vec![] as Vec<Entry>)
}

当我尝试以通用方式转换相同的逻辑时,出现编译错误。

fn query<'a, T: From<&'a Row>>(client: &mut Client, query_str: &str, params: &[&(dyn ToSql + Sync)]) -> Vec<T>  {
  let rows = client.query(query_str, params)
    .unwrap_or(vec![] as Vec<Row>);
  rows
    .iter()
    .map(|r: &'a Row| {
      T::from(r)
    })
    .collect()
}

我会说逻辑是相等的,我看不出有什么不同,但是生命周期定义不正确。

我是不是错过了一个特质或类似的东西?

    |
238 | fn query<'a, T: From<&'a Row>>(client: &mut Client, query_str: &str, params: &[&(dyn ToSql + Sync)]) -> Vec<T> {
    |          -- lifetime `'a` defined here
...
241 |       rows
    |       ^^^^ borrowed value does not live long enough
...
244 |           T::from(r)
    |           ---------- argument requires that `rows` is borrowed for `'a`
...
247 |     })
    |     - `rows` dropped here while still borrowed

编辑:

我将代码简化为这个例子,也许它更有帮助。

fn convert<'a, T: From<&'a abc>>() -> Vec<T> {
    let abcs = vec![abc::new(), abc::new(), abc::new(), abc::new()];
    abcs
        .iter()
        .map(|f| {
            T::from(f)
        })
        .collect()
}

这里是错误:

error[E0597]: `abcs` does not live long enough
  --> src/main.rs:43:5
   |
41 | fn convert<'a, T: From<&'a abc>>() -> Vec<T> {
   |            -- lifetime `'a` defined here
42 |     let abcs = vec![abc::new(), abc::new(), abc::new(), abc::new()];
43 |     abcs
   |     ^^^^ borrowed value does not live long enough
...
46 |             T::from(f)
   |             ---------- argument requires that `abcs` is borrowed for `'a`
...
49 | }
   | - `abcs` dropped here while still borrowed


我一直想找出问题所在,但我做不到。您是否尝试查找任何拼写错误?我不明白代码,但我给你答案的原因是因为我的朋友可能会理解它。好吧,所以他说你可能错过了一个特征,但他不能说出是哪个特征或问题是什么。他建议查看一下,我以前忘记在我的程序中添加代码,并且拼写错误。查看我的代码几乎总是对我有帮助。

当您指定

fn convert<'a, T: From<&'a abc>>() -> Vec<T>

你基本上是在断言 T 只为那些 abc 的引用实现 From<&abc>,这些引用的生命周期 超过 函数。

您可以假设您的函数具有以下隐式生命周期(此处以伪代码表示):

fn convert<'a, T: From<&'a abc>>() -> Vec<T> {
    'b : {
        let abcs = vec![abc::new(), abc::new(), abc::new(), abc::new()];
        abcs
            .iter()
            .map(|f| {
                T::from(f)
            })
            .collect()
    }
}

abcs 属于隐式生命周期 "'b",它小于 'a,因此不能引用其中一个元素满足From<&'a abc>>。鉴于您 必须 在约束 T: From<&'a abc> 时指定生命周期,没有简单的方法可以解决这个问题。

编译器拒绝此代码是有意义的,因为它无法确保 T: From<&'a abc> 中的 From::from 不会生成不包含其引用的 T创建自。

你的函数也会接受类似下面的内容

struct X<'a> {
    r: &' abc
}

impl <'a> From<&'a abc> for X<'a> {
    fn from(r: &'a abc) -> Self {
        Self { r }
    }
}

但由于 convert 返回包含对 abc.

的本地实例的引用的 Vec<X>,它会被破坏

您正在寻找的是所谓的“高级特征绑定”。 (参见 here

for<'a> can be read as "for all choices of 'a", and basically produces an infinite list of trait bounds that F must satisfy

这似乎是您想要的,因为您可以指定比 convert 的生命周期“更小”的生命周期。 在您的示例中,这看起来像:

fn convert< T: for<'a> From<&'a abc>>() -> Vec<T> {
    let abcs = vec![abc::new(), abc::new(), abc::new(), abc::new()];
    abcs
        .iter()
        .map(|f| {
            T::from(f)
        })
        .collect()
}