Ограничивающий параметр generi c структуры Rust для десериализации - PullRequest
3 голосов
/ 10 января 2020

Я хотел бы ограничить (де) сериализуемую структуру, чтобы иметь универсальный параметр c, который также десериализуем. Макрос производных Deserialize не требует, чтобы я добавил это ограничение, что приятно, но я бы хотел, чтобы код интеграции получал ошибки компиляции, даже если они никогда не пытаются десериализовать структуру, определенную в библиотеке.

use failure::Fallible; // 0.1.6
use serde::{Deserialize, Serialize}; // 1.0.104
use serde_json::to_string_pretty; // 1.0.44

#[derive(Deserialize, Serialize)]
struct X<T>
where
    // T: Serialize,
{
    a: u8,
    t: T,
}

type Main<'a> = &'a dyn Fn() -> Fallible<()>;

fn main() -> Fallible<()> {
    let x = X { a: 1, t: false };
    println!("{}", to_string_pretty(&x)?);

    let y: X<bool> = serde_json::from_str(r#"{"a":2,"t":true}"#)?;
    println!("{}", y.t);

    let _z: X<Main> = X { a: 3, t: &main };
    // println!("{}", to_string_pretty(&z)?);

    //let w: X<Main> = serde_json::from_str(r#"{"a":4,"t":NONONO}"#)?;

    Ok(())
}

детская площадка

  • Компиляция завершится неудачно, если я раскомментирую строку с to_string_pretty(&z), что хорошо.
  • Даже без этой строки компиляция завершится неудачно в строке let _z = ..., если я раскомментирую where T: Serialize. Это здорово, потому что это помогает интеграторам библиотек определить, что они используют struct X с параметром несериализуемого типа, даже до того, как они фактически начнут его сериализовать.

Я пытался добавить where for<'a> T: serde::de::Deserialize<'a> в качестве ограничения на struct X<T>, но это нарушает сборку даже без чего-либо, используя X

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct X<T>
where
    for<'a> T: serde::de::Deserialize<'a>,
{
    a: u8,
    t: T,
}

детская площадка

Есть ли способ сформулировать это ограничение Я ищу?

1 Ответ

4 голосов
/ 10 января 2020

Вам необходимо использовать #[serde(bound)], чтобы Serde не пытался автоматически определять границы для реализаций Deserialize и Serialize:

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
#[serde(bound = "T: Serialize, for<'de2> T: Deserialize<'de2>")]
struct X<T>
where
    T: Serialize,
    for<'de2> T: Deserialize<'de2>,
{
    t: T,
}

struct NotSerializable;

fn main() {
    X { t: true };

    // X { t: NotSerializable }; // Generates compiler error
}

См. Также:

...