是否可以使用 Serde / Rust 全局处理无效的 JSON 值?

Is it possible to to handle invalid JSON values globally using Serde / Rust?

提问人:user2297996 提问时间:9/27/2023 最后编辑:Chayim Friedmanuser2297996 更新时间:9/27/2023 访问量:87

问:

我的意思是:

给定此结构:

struct SomeObj {
  someProp: bool
}

有没有办法强制Serde在JSON输入中的值不是布尔值时分配true / false?someProp

通常,在这种情况下,serde 只会返回错误(无效类型,预期的 XY。等)。但是,是否可以抑制错误并仅提供一些有意义的默认值?

我知道这是可能的,比如:

#[serde(from = "serde_json::Value")]
struct SomeObj {
  someProp: bool
}

impl From<serde_json::Value> for SomeObj {
...
}

但是我需要处理大量复杂而庞大的结构,因此在全球范围内处理这个问题会容易得多。

rust serde serde-json

评论

0赞 Chayim Friedman 9/27/2023
您想接受其他类型,例如字符串或 ,并将其转换为布尔值吗?"yes""no"
0赞 user2297996 9/27/2023
不。我想将每个非布尔类型转换为false。
0赞 user2297996 9/27/2023
换句话说,我希望 serde 接受 true 或 false,其他所有内容都应该转换为布尔值 false。

答:

2赞 Silvio Mayolo 9/27/2023 #1

您始终可以使用属性 deserialize_with 覆盖对反序列化程序的选择。此属性接受一个函数,该函数将用于反序列化,而不是通常的特征。serdeDeserialize

#[derive(Serialize, Deserialize)]
struct SomeObj {
  #[serde(deserialize_with = "deserialize_bool_or_false")]
  someProp: bool
}

fn deserialize_bool_or_false<'de, D>(deserializer: D) -> Result<bool, D::Error>
where D: Deserializer<'de> {
  let deserialized = bool::deserialize(deserializer);
  // deserialized is a Result<bool, ...>. You can handle the error
  // case however you like. This example simply returns false.
  Ok(deserialized.unwrap_or(false))
}

您只需将该属性附加到要自定义默认行为的每个字段。deserialize_with

如果您愿意引入额外的依赖项,serde_with库具有 DefaultOnError,如果该字段发生任何反序列化错误,它将返回类型(即 、 、 、 等)的 Default::d efault() 值。因此,使用该结构,您可以将任何字段标记为 并且,只要基础类型实现了 trait ,它就会起作用。false""00.0#[serde_as(deserialize_as = "DefaultOnError")]Default

#[serde_as]
#[derive(Serialize, Deserialize)]
struct SomeObj {
  #[serde_as(deserialize_as = "DefaultOnError")]
  someProp: bool
}

这将适用于任何有符号或无符号整数类型、浮点类型、字符串以及任何满足 .boolDefault

评论

0赞 user2297996 9/27/2023
谢谢。这听起来比为每个结构/枚举实现 From 要好得多。但我想这仍然意味着我必须创建一堆自定义反序列化程序,然后手动将它们附加到每个字段。所以没有“简单的方法”可以解决这个问题,对吧?就像以某种方式告诉 serde 如何处理布尔值、字符串、数字等字段一次,然后在任何地方使用它。
0赞 Silvio Mayolo 9/27/2023
@user2297996 看看我刚刚对答案所做的编辑。我以为可以干净利落地做到这一点,我找到了。 应该适用于几乎任何合理的 JSON 类型,只要您想要的“默认”值是由 Rust 的特征定义的值。serde_withDefaultOnErrorDefault
0赞 user2297996 9/27/2023
完善!谢谢,这听起来很棒!我会这样做的。