2017-10-09 17 views
4

J'essaie d'écrire un trait qui fonctionne avec une base de données et représente quelque chose qui peut être stocké. Pour ce faire, le trait hérite des autres, ce qui inclut le trait serde::Deserialize.Comment créer une fonction générique dans Rust avec un trait nécessitant une durée de vie?

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] } 
} 

Ensuite, je suis en train d'écrire ces données en utilisant une fonction générique:

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()) 
} 

Cependant, je reçois l'erreur suivante:

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.

Comment est-ce que je résoudrais cela, peut-être l'éviterais-je tout à fait?

Répondre

3

Vous avez défini Storable avec un paramètre générique, dans ce cas une durée de vie. Cela signifie que le paramètre générique doit être propagé dans l'ensemble de l'application:

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

Vous pouvez également décider de rendre le générique spécifique. Cela peut être fait avec un type concret ou une durée de vie (par exemple, 'static), ou en le plaçant derrière un objet trait. Serde a également a comprehensive page about deserializer lifetimes. Il mentionne que vous pouvez également utiliser DeserializeOwned.

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

Vous pouvez utiliser le même concept que DeserializeOwned pour votre propre trait ainsi:

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

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

Vous avez la durée de vie 'de au mauvais endroit - vous en avez besoin pour spécifier l'argument à Storable, pas la durée de vie de la référence obj.

Au lieu de

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

utilisation

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

Playground.

La durée de vie de obj n'a pas vraiment d'importance ici, car vous ne renvoyez aucune valeur dérivée. Tout ce que vous devez prouver est que S implémente Storable<'de> pour une durée de vie 'de.

Si vous souhaitez éliminer complètement le 'de, vous devez utiliser DeserializeOwned, comme décrit par the other answer.