Rust自定义反序列化实现
Rust custom deserialize implementation
我很难理解如何使用 Rust 的 serde 为自定义映射实现反序列化。如果有人能帮我解决这个例子,我会很高兴:
我有以下结构:
#[derive(Debug, Clone, PartialEq)]
pub struct ConnectorTopics {
pub name: String,
pub topics: Vec<String>,
}
并且 JSON 数据采用以下格式:
{
"test-name": {
"topics": [
"topic1",
"topic2"
]
}
}
如您所见,name
字段是主题的包装器,因此在我的例子中,这应该反序列化为:
let _ = ConnectorTopics {
name: "test-name".into(),
topics: vec!["topic1".into(), "topic2".into()]
}
我的第一次尝试是在反序列化实现中使用自定义结构,但是,这不会编译并且似乎不是正确的方法。
impl<'de> Deserialize<'de> for ConnectorTopics {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Debug, Deserialize)]
struct Inner {
topics: Vec<String>,
}
let a = deserializer.deserialize_map(HashMap<String, Inner>).unwrap();
let value = Deserialize::deserialize::<HashMap<String, Inner>>(deserializer)?;
let (connector, inner) = value.iter().nth(0).ok_or("invalid")?.0;
Ok(ConnectorTopics {
name: connector,
topics: vec![],
})
}
}
您可以为其使用自定义函数:
pub fn deserialize_connector_topics(data: &str) -> Result<ConnectorTopics> {
let value: Value = serde_json::from_str(data)?;
if let Some(object) = value.as_object() {
let mut it = object.into_iter();
if let Some((name, topics)) = it.next() {
let topics: Vec<String> = serde_json::from_value(topics.get("topics").unwrap().clone())?;
return Ok(ConnectorTopics {
name: name.to_string(),
topics: topics,
});
}
};
Err(Error::custom("Invalid ConnectorTopics data"))
}
请注意,它非常特别,甚至到处都有一些解包和(可能是不必要的)克隆。您应该考虑根据您的需要修改它。不过举个例子,应该够了。
您的做法是正确的,但是您的 json 很奇怪:
use serde::de;
use serde::Deserialize;
use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub struct ConnectorTopics {
pub name: String,
pub topics: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct Inner {
topics: Vec<String>,
}
impl<'de> de::Deserialize<'de> for ConnectorTopics {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct ConnectorTopicsVisitor;
impl<'de> de::Visitor<'de> for ConnectorTopicsVisitor {
type Value = ConnectorTopics;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("ConnectorTopics")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
if let Some(key) = map.next_key()? {
let value: Inner = map.next_value()?;
if let Some(_) = map.next_key::<&str>()? {
Err(de::Error::duplicate_field("name"))
} else {
Ok(Self::Value {
name: key,
topics: value.topics,
})
}
} else {
Err(de::Error::missing_field("name"))
}
}
}
deserializer.deserialize_map(ConnectorTopicsVisitor {})
}
}
fn main() {
let input = r#"{
"test-name": {
"topics": [
"topic1",
"topic2"
]
}
}"#;
let result: ConnectorTopics = serde_json::from_str(input).unwrap();
let expected = ConnectorTopics {
name: "test-name".into(),
topics: vec!["topic1".into(), "topic2".into()],
};
assert_eq!(result, expected);
}
我很难理解如何使用 Rust 的 serde 为自定义映射实现反序列化。如果有人能帮我解决这个例子,我会很高兴:
我有以下结构:
#[derive(Debug, Clone, PartialEq)]
pub struct ConnectorTopics {
pub name: String,
pub topics: Vec<String>,
}
并且 JSON 数据采用以下格式:
{
"test-name": {
"topics": [
"topic1",
"topic2"
]
}
}
如您所见,name
字段是主题的包装器,因此在我的例子中,这应该反序列化为:
let _ = ConnectorTopics {
name: "test-name".into(),
topics: vec!["topic1".into(), "topic2".into()]
}
我的第一次尝试是在反序列化实现中使用自定义结构,但是,这不会编译并且似乎不是正确的方法。
impl<'de> Deserialize<'de> for ConnectorTopics {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Debug, Deserialize)]
struct Inner {
topics: Vec<String>,
}
let a = deserializer.deserialize_map(HashMap<String, Inner>).unwrap();
let value = Deserialize::deserialize::<HashMap<String, Inner>>(deserializer)?;
let (connector, inner) = value.iter().nth(0).ok_or("invalid")?.0;
Ok(ConnectorTopics {
name: connector,
topics: vec![],
})
}
}
您可以为其使用自定义函数:
pub fn deserialize_connector_topics(data: &str) -> Result<ConnectorTopics> {
let value: Value = serde_json::from_str(data)?;
if let Some(object) = value.as_object() {
let mut it = object.into_iter();
if let Some((name, topics)) = it.next() {
let topics: Vec<String> = serde_json::from_value(topics.get("topics").unwrap().clone())?;
return Ok(ConnectorTopics {
name: name.to_string(),
topics: topics,
});
}
};
Err(Error::custom("Invalid ConnectorTopics data"))
}
请注意,它非常特别,甚至到处都有一些解包和(可能是不必要的)克隆。您应该考虑根据您的需要修改它。不过举个例子,应该够了。
您的做法是正确的,但是您的 json 很奇怪:
use serde::de;
use serde::Deserialize;
use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub struct ConnectorTopics {
pub name: String,
pub topics: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct Inner {
topics: Vec<String>,
}
impl<'de> de::Deserialize<'de> for ConnectorTopics {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct ConnectorTopicsVisitor;
impl<'de> de::Visitor<'de> for ConnectorTopicsVisitor {
type Value = ConnectorTopics;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("ConnectorTopics")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
if let Some(key) = map.next_key()? {
let value: Inner = map.next_value()?;
if let Some(_) = map.next_key::<&str>()? {
Err(de::Error::duplicate_field("name"))
} else {
Ok(Self::Value {
name: key,
topics: value.topics,
})
}
} else {
Err(de::Error::missing_field("name"))
}
}
}
deserializer.deserialize_map(ConnectorTopicsVisitor {})
}
}
fn main() {
let input = r#"{
"test-name": {
"topics": [
"topic1",
"topic2"
]
}
}"#;
let result: ConnectorTopics = serde_json::from_str(input).unwrap();
let expected = ConnectorTopics {
name: "test-name".into(),
topics: vec!["topic1".into(), "topic2".into()],
};
assert_eq!(result, expected);
}