Serde lifetimes conflicts


#1

I have this simple struct below that I wanted to deserialize using serde. but it gave me conflicting lifetime error. I don’t understand how that error shows up

#[derive(Serialize, Deserialize)]
pub struct Transaction<'a> {
    timestamp: i64,
    next: Option<&'a str>,
    prev: Option<&'a str>,
}

Error:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
  |
note: first, the lifetime cannot outlive the lifetime 'de as defined on the impl at 4:21...
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
note: ...so that types are compatible (expected serde::de::SeqAccess<'_>, found serde::de::SeqAccess<'de>)
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 4:21...
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
note: ...so that types are compatible (expected serde::Deserialize<'_>, found serde::Deserialize<'_>)
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
  |
note: first, the lifetime cannot outlive the lifetime 'de as defined on the impl at 4:21...
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
note: ...so that types are compatible (expected serde::de::MapAccess<'_>, found serde::de::MapAccess<'de>)
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 4:21...
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^
note: ...so that types are compatible (expected serde::Deserialize<'_>, found serde::Deserialize<'_>)
 --> src/main.rs:4:21
  |
4 | #[derive(Serialize, Deserialize)]
  |                     ^^^^^^^^^^^

#2

I think you need to add borrow attributes:

#[derive(Serialize, Deserialize)]
pub struct Transaction<'a> {
    timestamp: i64,
    #[serde(borrow)]
    next: Option<&'a str>,
    #[serde(borrow)]
    prev: Option<&'a str>,
}

Need help with lifetime declaration
#3

yup, I found out that was the fix indeed. But I don’t really fully understand the problem, and was looking for an elaborative explanation?


#4

#[serde(borrow)] is an implementation detail, because lifetimes need special handling in Serde.

Are you sure you require to use temporary borrows here? Rust’s references are not used like pointers in C. References are more like compile-time read/write locks. So 99% of the time structs use owned values, and String may be what you want.


#5

Deserializer lifetimes are described here. When you have a struct that’s borrowing from the deserializer, which has a 'de lifetime parameter, the #[serde(borrow)] attribute instructs the proc macro to add a lifetime bound specifying that 'de outlives the lifetime parameter on the field. This is to enforce that the data the deserializer has, which is being borrowed from, won’t vanish from underneath the borrows in your struct.

In your case the lifetime parameter is 'a - the macro will then generate a 'de: 'a bound on the Deserialize impl for the struct.

That’s as much as I know about this - @dtolnay is the expert on this and may have more to say.