返回Box <future>的操作的生命周期编译器错误

时间:2017-10-24 18:21:38

标签: rust future associated-types

我正在尝试使用带有futures包的tokio进行异步操作,并且没有任何问题。现在我实现了一个异步加载数据然后执行一些转换的存储,但我的界面似乎有一些我无法理解的生命周期问题。

这是一个减少的测试代码,显示相同的症状;真正的函数体执行比总是返回错误更合理的操作:

extern crate futures;

use futures::prelude::*;
use futures::future;

pub enum MyError {
    SomeError,
}

pub trait KeyValueStore {
    type ValueType;

    fn load(&self, key: String) -> Box<Future<Item = Vec<u8>, Error = MyError>>;
    fn deserialize(&self, serialized_obj: Vec<u8>) -> Result<Self::ValueType, MyError>;

    fn resolve(&self, key: String) -> Box<Future<Item = Self::ValueType, Error = MyError>>;
}

pub struct Storage<Obj> {
    _unused: std::marker::PhantomData<Obj>,
}

impl<Obj: 'static> KeyValueStore for Storage<Obj> {
    type ValueType = Obj;

    fn deserialize(&self, serialized_obj: Vec<u8>) -> Result<Self::ValueType, MyError> {
        Err(MyError::SomeError)
    }

    fn load(&self, key: String) -> Box<Future<Item = Vec<u8>, Error = MyError>> {
        Box::new(future::err(MyError::SomeError))
    }

    fn resolve(&self, key: String) -> Box<Future<Item = Self::ValueType, Error = MyError>> {
        let result = self.load(key).and_then(|bytes| self.deserialize(bytes));
        Box::new(result)
    }
}

编译器拒绝此示例代码时出现以下生命周期问题:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:36:9
   |
36 |         Box::new(result)
   |         ^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 34:5...
  --> src/main.rs:34:5
   |
34 | /     fn resolve(&self, key: String) -> Box<Future<Item = Self::ValueType, Error = MyError>> {
35 | |         let result = self.load(key).and_then(|bytes| self.deserialize(bytes));
36 | |         Box::new(result)
37 | |     }
   | |_____^
note: ...so that the type `futures::AndThen<std::boxed::Box<futures::Future<Error=MyError, Item=std::vec::Vec<u8>>>, std::result::Result<Obj, MyError>, [closure@src/main.rs:35:46: 35:77 self:&&Storage<Obj>]>` will meet its required lifetime bounds
  --> src/main.rs:36:9
   |
36 |         Box::new(result)
   |         ^^^^^^^^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Error=MyError, Item=Obj> + 'static>, found std::boxed::Box<futures::Future<Error=MyError, Item=Obj>>)
  --> src/main.rs:36:9
   |
36 |         Box::new(result)
   |         ^^^^^^^^^^^^^^^^

以前用hypertokio-postgres编写的代码似乎有相同的逻辑,但从未产生过这样的错误。我甚至无法在没有参考的情况下看到这里的生命可能出错的地方。我的直觉表明它与通用Obj参数有某种关系,静态生命周期限制感觉不对。

什么情况导致编译错误?

1 个答案:

答案 0 :(得分:3)

self中的self.deserialize需要从&self参数到resolve的生命周期;结果不能标记为Box<Future<..>>,这对于装箱'static生命周期需要Future

您可以使用Box<Future<..> + 'a>覆盖框装未来的生命周期要求(其中'aself参数的生命周期;您需要更改{{1}特征和实现中的签名);但是你没有太多可以对结果做的事情,因为通常基于resolve的事件循环对于他们必须运行的Future生命周期需要'static

相反,您可以通过Future一个&#34;静态方法&#34;来解决此问题,即删除deserialize参数并通过&self调用它。

将traits用作类型时的默认生存期要求(在本例中为Self::deserialize)记录在参考中的Trait objects中。