1

I am trying to declare a struct that contains another struct of any given type that can be Deserialize and Serialize.

#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T: Deserialize + Serialize> {
    pub data: T,
}

Rust playground.

For that, I have tried to use trait bounds, using traits such as DeserializeOwned or Deserialize. Both have failed at compilation time with the following errors:

error[E0283]: type annotations required: cannot resolve `T: serde::Deserialize<'de>`
 --> src/main.rs:9:28
  |
9 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^
  |
  = note: required by `serde::Deserialize`
error[E0637]: `&` without an explicit lifetime name cannot be used here
  --> src/main.rs:10:19
   |
10 | pub struct Foo<T: Deserialize + Serialize> {
   |                   ^^^^^^^^^^^ explicit lifetime name needed here

I faced errors trying to add a lifetime since I am not using storing a reference but a value.

What is the most idiomatic way of declaring this type of struct?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
tehAnswer
  • 960
  • 1
  • 13
  • 28

2 Answers2

1

I found a solution thanks to a member of the Rust Discord who referred me to the following Github issue. The trick is not to use trait bounds but attribute bounds.

#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T> {
    #[serde(bound(
        serialize = "T: Serialize",
        deserialize = "T: Deserialize<'de>",
    ))]
    pub data: T,
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
tehAnswer
  • 960
  • 1
  • 13
  • 28
1

Just don't place the bounds on the type:

use serde::{Deserialize, Serialize}; // 1.0.91

#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T> {
    pub data: T,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Boo {
    pub a: i64,
}

fn main() {
    let data = Boo { a: 1 };
    let wrap = Foo { data };
    println!("{:?}", wrap);
}

Then, place the bounds on methods where you need that behavior:

fn use_it<T>(foo: Foo<T>)
where
    Foo<T>: Serialize,
{
    // ...
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Can you elaborate on your suggestion on why it's preferable to add trait bounds on methods? I've certainly seen this before, for example with `Result` and the `Debug` trait which adds the `unwrap` method. At first glance, it seems that the code becomes less predictable to me. – tehAnswer Jun 30 '19 at 14:59
  • 1
    @tehAnswer I didn’t state it was preferable, just that it’s an option. See a related questions on [struct vs impl](https://stackoverflow.com/q/49229332/155423) and [impl vs method](https://stackoverflow.com/q/36142626/155423) for deeper discussion. – Shepmaster Jun 30 '19 at 15:23