将 Rust 结构体的通用参数限制为可反序列化

4
我希望限制一个(反)序列化的结构体只能有一个通用参数,并且该参数也必须可反序列化。自动生成的宏 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(())
}

Playground

  • 如果我取消注释带有to_string_pretty(&z)的行,编译将会失败,这是很好的。
  • 即使没有那一行,如果我取消注释where T: Serialize,编译也会在let _z = ...的一行失败。这是很好的,因为它帮助库集成者在开始序列化之前就发现他们正在使用一个非可序列化类型参数的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,
}

游乐场

有没有一种方式来表达我所寻求的约束条件?


你能否发布你想要运行的确切代码,并添加你遇到的错误信息?我不确定你想取消注释哪些行。 - trent
好的。尝试澄清对库代码的无效尝试。 - wigy
谢谢你的帮助!不幸的是,我仍然和你一样困惑... - trent
第一段代码证明您可以实例化X<Main>而不需要Main被反序列化。除非您实际上对X<Main>进行反序列化,否则不会出现错误。 - wigy
1个回答

9
您需要使用#[serde(bound)],以防止Serde尝试自动确定DeserializeSerialize实现的边界:
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
}

参考资料:


1
哇,谢谢。这个 Github 讨论 与 serde 的作者 dtolnay 也帮助理解为什么它会这样工作。 - wigy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接