gpt4 book ai didi

rust - 实现一个复杂的自定义结构序列化器

转载 作者:行者123 更新时间:2023-12-03 11:40:59 25 4
gpt4 key购买 nike

我正在试验Rust,并试图为Rust中的Elasticsearch查询编写包装器。我已经实现了一个查询,该查询可以正常运行,但是我真的不喜欢使用json!宏进行查询的方式。

fn main() {
let actual = Query {
field: "field_name".into(),
values: vec![1, 2, 3],
boost: Some(2),
name: Some("query_name".into()),
};

let expected = serde_json::json!({
"terms": {
"field_name": [1, 2, 3],
"boost": 2,
"_name": "query_name"
}
});

let actual_str = serde_json::to_string(&actual).unwrap();
let expected_str = serde_json::to_string(&expected).unwrap();

assert_eq!(actual_str, expected_str);
}

#[derive(Debug)]
struct Query {
field: String,
values: Vec<i32>,
boost: Option<i32>,
name: Option<String>,
}

impl serde::Serialize for Query {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let field = self.field.as_str();
let values = self.values.as_slice();

let value = match (&self.boost, &self.name) {
(None, None) => serde_json::json!({ field: values }),
(None, Some(name)) => serde_json::json!({ field: values, "_name": name }),
(Some(boost), None) => serde_json::json!({ field: values, "boost": boost }),
(Some(boost), Some(name)) => {
serde_json::json!({ field: values, "boost": boost, "_name": name })
}
};

serde_json::json!({ "terms": value }).serialize(serializer)
}
}
我想知道如何使用serde的内置特征(例如 SerializeStructSerializeMap等)来实现这样的序列化程序。基本上,我想避免使用json宏或创建中间数据结构。

最佳答案

如果使数据结构与JSON更加匹配,则可以使用几个#[serde]批注进行整个序列化,这些批注更易于维护,并且与手动实现相比不太可能变慢。 (编辑:动态命名的字段实际上使这一点变得棘手,因此在这种情况下,自定义Serialize的实现可能实际上是最好的)。
Serde序列化通过委派给Serialize的其他实现来工作,因此很难在单个实现中从平面结构创建自定义嵌套映射。
您可以为嵌套创建一个临时结构,如下所示:

// Need to import SerializeMap to call its methods
use serde::{Serialize, ser::SerializeMap};

// temporary wrapper for serializing Query as the inner object
struct InnerQuery<'a>(&'a Query);

impl<'a> serde::Serialize for InnerQuery<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let query = self.0;
// We don't know the length of the map at this point, so it's None
let mut map = serializer.serialize_map(None)?;
map.serialize_entry(&query.field, &query.values)?;
if let Some(boost) = &query.boost {
map.serialize_entry("boost", boost)?;
}
if let Some(name) = &query.name {
map.serialize_entry("_name", name)?;
}
map.end()
}
}
这将为您提供内在的部分:
{
"field_name": [1, 2, 3],
"boost": 2,
"_name": "query_name"
}
然后为主要结构实现序列化,如下所示:
impl serde::Serialize for Query {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("terms", &InnerQuery(&self))?;
map.end()
}
}
请注意,键的顺序不是确定性的,因此需要更改测试。一种方法是将其解析回 serde_json::Value,它将按照您的期望进行相等性比较:
let actual_str = serde_json::to_string(&actual).unwrap();
let actual: serde_json::Value = serde_json::from_str(&actual_str).unwrap();

assert_eq!(actual, expected);

关于rust - 实现一个复杂的自定义结构序列化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66322145/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com