2017-10-09 91 views
4

我想写一个与数据库一起工作的特征,并代表可以存储的东西。要做到这一点,这个特质继承了其他特征,其中包括serde::Deserialize特征。如何在Rust中创建一个需要终生特征的通用函数?

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.

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

回答

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> { 
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,则应使用DeserializeOwned,如the other answer所述。

相关问题