I am trying to write a trait which works with a database and represents something which can be stored. To do this, the trait inherits from others, which includes the serde::Deserialize trait.
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] }
}
Next, I am trying to write this data using a generic function:
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())
}
However, I am getting the following error:
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.
How would I resolve this, possibly avoid it altogether?
You have defined Storable with a generic parameter, in this case a lifetime. That means that the generic parameter has to be propagated throughout the entire application:
fn put<'de, S: Storable<'de>>(obj: &'de S) -> Result<(), String> { /* ... */ }
You can also decide to make the generic specific. That can be done with a concrete type or lifetime (e.g. 'static), or by putting it behind a trait object.
Serde also has a comprehensive page about deserializer lifetimes. It mentions that you can choose to use DeserializeOwned as well.
trait Storable: Serialize + DeserializeOwned { /* ... */ }
You can use the same concept as DeserializeOwned for your own trait as well:
trait StorableOwned: for<'de> Storable<'de> { }
fn put<'de, S: StorableOwned>(obj: &'de S) -> Result<(), String> {
You have the 'de lifetime in the wrong place -- you need it to specify the argument to Storable, not the lifetime of the reference obj.
Instead of
fn to_json<'de, S: Storable>(obj: &'de S) -> String {
use
fn to_json<'de, S: Storable<'de>>(obj: &S) -> String {
Playground.
The lifetime of obj doesn't actually matter here, because you're not returning any values derived from it. All you need to prove is that S implements Storable<'de> for some lifetime 'de.
If you want to eliminate the 'de altogether, you should use DeserializeOwned, as the other answer describes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With