serde-rs / serde

Serialization framework for Rust
https://serde.rs/
Apache License 2.0
8.81k stars 747 forks source link

#[serde(skip_deserializing)] for Option<T> wrongly requires T to implement Default #2759

Open SylvainGarrigues opened 2 weeks ago

SylvainGarrigues commented 2 weeks ago

Quoting the documentation for #[serde(skip_deserializing)]: When deserializing, Serde will use Default::default() or the function given by default = "..." to get a default value for this field.

Option<T> defaults to None event if T doesn't implement Default, so why does the compiler complain T must implement such Default trait for me to be able to derive Deserialize?

Sample code (uncomment /* Default */ to have the code compile):

use serde::Deserialize;
use std::fmt::Debug;

#[derive(Debug /*, Default*/)]
struct Hidden(());

#[derive(Deserialize)]
struct Config<T> {
    ip: String,
    #[serde(skip_deserializing)]
    hidden: Option<T>,
}

fn load_config<T /*: Default*/>(s: &str) -> Config<T> {
    toml::from_str(s).unwrap()
}

fn main() {
    let config: Config<Hidden> = load_config(r#"ip = '127.0.0.1'"#);
    println!("ip={:?}, hidden={:?}", config.ip, config.hidden);
}

Same code in Rust playground

SylvainGarrigues commented 2 weeks ago

Oddly enough, I noticed that in my case, manually specifying the default function to Default::default() makes the code compile without restraining T to implement Default:

#[serde(skip_deserializing, default = "Default::default")]
Mingun commented 2 weeks ago

This is because serde_derive constraints generic types of the struct (T) to required traits instead of actual types of fields (Option<T>).