如何在Rust中创建一个具有生命周期特征的泛型函数?

时间:2017-10-09 19:14:38

标签: rust traits lifetime

我正在尝试编写一个与数据库一起使用的特征,并表示可以存储的内容。为此,特征继承自其他特征,其中包括serde::Deserialize特征。

trait Storable<'de>: Serialize + Deserialize<'de> {
    fn global_id() -> &'static [u8];
    fn instance_id(&self) -> Vec<u8>;
}

struct Example {
    a: u8,
    b: u8
}

impl<'de> Storable<'de> for Example {
    fn global_id() -> &'static [u8] { b"p" }
    fn instance_id(&self) -> Vec<u8> { vec![self.a, self.b] }
}

接下来,我尝试使用通用函数编写此数据:

pub fn put<'de, S: Storable>(&mut self, obj: &'de S) -> Result<(), String> {
    ...
    let value = bincode::serialize(obj, bincode::Infinite);
    ...
    db.put(key, value).map_err(|e| e.to_string())
}

但是,我收到以下错误:

error[E0106]: missing lifetime specifier
--> src/database.rs:180:24
    |
180 |     pub fn put<'de, S: Storable>(&mut self, obj: &'de S) -> Result<(), String> {
    |                        ^^^^^^^^ expected lifetime parameter

Minimal example on the playground.

我如何解决这个问题,可能完全避免它?

2 个答案:

答案 0 :(得分:4)

您的'de生命周期在错误的位置 - 您需要它来指定Storable的参数,而不是参考obj的生命周期。

而不是

fn to_json<'de, S: Storable>(obj: &'de S) -> String {

使用

fn to_json<'de, S: Storable<'de>>(obj: &S) -> String {

Playground

obj的生命周期在这里并不重要,因为你没有返回从它派生的任何值。您需要证明的是S实施Storable<'de>一生'de

如果您想完全取消'de,则应使用DeserializeOwnedthe other answer描述。

答案 1 :(得分:3)

您已使用通用参数定义Storable,在本例中为生命周期。这意味着通用参数必须在整个应用程序中传播:

fn put<'de, S: Storable<'de>>(obj: &'de S) -> Result<(), String> { /* ... */ }

您还可以决定制作通用的特定内容。这可以通过具体类型或生命周期(例如'static)完成,或者将其放在特征对象后面。

Serde也有a comprehensive page about deserializer lifetimes。它提到您也可以选择使用DeserializeOwned

trait Storable: Serialize + DeserializeOwned { /* ... */ }

您也可以使用与DeserializeOwned相同的概念来表达自己的特征:

trait StorableOwned: for<'de> Storable<'de> { }

fn put<'de, S: StorableOwned>(obj: &'de S) -> Result<(), String> {