在 Rust 1.26 中推断存在类型(impl Trait)的生命周期

Inferring lifetime for existential type (impl Trait) in Rust 1.26

我正在尝试重写一个方法以使用存在类型,但我在破译错误时遇到了问题:

use std::result;

pub struct Child {
    pub value: u32,
}

pub struct Parent {
    pub name: u32,
}

impl Parent {
    pub fn process(&self, _l: &Child) -> result::Result<(), ()> {
        Ok(())
    }

    pub fn convert(&self, l: &Child) {
        ()
    }

    pub fn looper(&self, l: Vec<Child>) -> impl Iterator<Item = Result<Child, ()>> {
        let x: Vec<_> = l.into_iter()
            .map(|tr| self.process(&tr).map(|_| tr))
            .collect(); // Calling collect() here forces all debits to complete

        let y = x.into_iter().map(|d| {
            d.map(|c| {
                self.convert(&c);
                c
            })
        });
        y
    }
}

fn main() {
    let b = Parent { name: 0 };
    let l = vec![Child { value: 10 }, Child { value: 20 }];
    let _: Vec<Child> = b.looper(l).map(|x| x.unwrap()).collect();
}

我的错误消息指出:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:25:35
   |
25 |           let y = x.into_iter().map(|d| {
   |  ___________________________________^
26 | |             d.map(|c| {
27 | |                 self.convert(&c);
28 | |                 c
29 | |             })
30 | |         });
   | |_________^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 20:5...
  --> src/main.rs:20:5
   |
20 | /     pub fn looper(&self, l: Vec<Child>) -> impl Iterator<Item = Result<Child, ()>> {
21 | |         let x: Vec<_> = l.into_iter()
22 | |             .map(|tr| self.process(&tr).map(|_| tr))
23 | |             .collect(); // Calling collect() here forces all debits to complete
...  |
31 | |         y
32 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&Parent
              found &&Parent
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that return value is valid for the call
  --> src/main.rs:20:44
   |
20 |     pub fn looper(&self, l: Vec<Child>) -> impl Iterator<Item = Result<Child, ()>> {
   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
let y = x.into_iter().map(|d| {
    d.map(|c| {
        self.convert(&c); // <--- This
         c
    })
});

这里在返回的迭代器中借用了&self,因为每次调用convert时,都需要将&self的一个实例传递给函数(即使没有使用).

要明确使生命周期正确,您需要的语法是:

fn foo<'a>(/* ... */) -> impl 'a + Trait

例如

pub fn looper<'a>(&'a self, l: /* ... */) -> impl 'a + Iterator<Item = Result<Child, ()>> { /* ... */ }

即Return 与借用对象具有相同生命周期的 impl Iterator<Item = Result<Child, ()>>

默认是impl Foo returns一个'static生命周期实例,在这种情况下是无效的,因为convert借用了&self

像这样:

use std::result;

pub struct Child {
    pub value: u32,
}

pub struct Parent {
    pub name: u32,
}

impl Parent {
    pub fn process(&self, _l: &Child) -> result::Result<(), ()> {
        Ok(())
    }

    pub fn convert(&self, l: &Child) {
        ()
    }

    pub fn looper<'a>(&'a self, l: Vec<Child>) -> impl 'a + Iterator<Item = Result<Child, ()>> {
        let x: Vec<_> = l.into_iter()
            .map(|tr| self.process(&tr).map(|_| tr))
            .collect(); // Calling collect() here forces all debits to complete

        let y = x.into_iter().map(move |d| {
            d.map(|c| {
                self.convert(&c);
                c
            })
        });
        y
    }
}

fn main() {
    let b = Parent { name: 0 };
    let l = vec![Child { value: 10 }, Child { value: 20 }];
    let k = b.looper(l);
    drop(b); // <-- Doesn't work.
    let _: Vec<Child> = k.map(|x| x.unwrap()).collect();
}

注意编译器正确地抱怨在迭代器未解析时尝试丢弃 b

error[E0505]: cannot move out of `b` because it is borrowed
  --> src/main.rs:39:10
   |
38 |     let k = b.looper(l);
   |             - borrow of `b` occurs here
39 |     drop(b);
   |          ^ move out of `b` occurs here

或者,您可以从 convert 中删除对 &self 的引用:

pub fn convert(l: &Child) {
    ()
}