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

时间:2018-05-15 18:56:55

标签: rust traits

我试图重写一种使用存在类型的方法,但我无法破译错误:

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, ()>> {
   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 个答案:

答案 0 :(得分:2)

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

这会在返回的迭代器中借用&self,因为每次调用convert时,都需要将&self的实例传递给函数(即使它未使用)。

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

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

e.g。

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

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

默认情况是impl Foo返回'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

或者,您可以从&self

中删除对convert的引用
pub fn convert(l: &Child) {
    ()
}