Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 用serde反序列化json,使用数值作为类型标识符_Rust_Enums_Json Deserialization_Serde - Fatal编程技术网

Rust 用serde反序列化json,使用数值作为类型标识符

Rust 用serde反序列化json,使用数值作为类型标识符,rust,enums,json-deserialization,serde,Rust,Enums,Json Deserialization,Serde,我是个新手,来自OOP背景。所以,也许我误解了一些基本原理 我想用serde解析一个固定的json结构。此结构表示一种不同的消息类型。每条消息都有一个数字类型属性来区分它。各个消息类型的确切结构差别很大,但它们也可以是相同的 {"type": 1, "sender_id": 4, "name": "sender", ...} {"type": 2, "sender_id": 5

我是个新手,来自OOP背景。所以,也许我误解了一些基本原理

我想用serde解析一个固定的json结构。此结构表示一种不同的消息类型。每条消息都有一个数字
类型
属性来区分它。各个消息类型的确切结构差别很大,但它们也可以是相同的

{"type": 1, "sender_id": 4, "name": "sender", ...}
{"type": 2, "sender_id": 5, "measurement": 3.1415, ...}
{"type": 3, "sender_id": 6, "measurement": 13.37, ...}
...
首先,我定义了一个
enum
来区分消息类型,对于每种类型的消息,我还定义了一个
struct
,没有存储类型的字段

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
enum Message {
    T1(Type1),
    T2(Type2),
    T3(Type3),
    // ...
}

#[derive(Debug, Serialize, Deserialize)]
struct Type1 {
    sender_id: u32,
    name: String,
    // ...
}
#[derive(Debug, Serialize, Deserialize)]
struct Type2 {
    sender_id: u32,
    measurement: f64,
    // ...
}
#[derive(Debug, Serialize, Deserialize)]
struct Type3 {
    sender_id: u32,
    measurement: f64,
    // ...
}
// ...
当我试图将字符串转换为
消息
对象时,我得到一个错误

let message = r#"{"type":1,"sender_id":123456789,"name":"sender"}"#;
let message: Message = serde_json::from_str(message)?; // error here
// Error: Custom { kind: InvalidData, error: Error("invalid type: integer `1`, expected variant identifier", line: 1, column: 9) }
所以,据我所知,serde试图找出当前消息的类型,但它需要一个字符串 为此。我还尝试编写自己的
反序列化()
-函数。我试图得到数值 对应的
类型的
-键,并希望通过类型值创建特定对象

如何实现
反序列化()
以提取消息类型并创建特定的消息对象?是否可以在不为每个
类型1/2/3/…
结构编写
反序列化()函数的情况下编写此函数

impl<'de> Deserialize<'de> for Message {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                  where D: Deserializer<'de>,
{
    // which functions I have to call?
}
impl for Message{
fn反序列化(反序列化程序:D)->结果

其中D:DeserializerSerde还不支持整数标记(请参阅)


如果您能够更改生成数据的内容,那么如果您能够将
类型
更改为字符串,即
“1”
而不是
1
。那么您只需使用

#[派生(调试、序列化、反序列化)]
#[serde(tag=“type”)]
枚举消息{
#[serde(rename=“1”)]
T1(类型1),
#[serde(rename=“2”)]
T2(第2类),
#[serde(rename=“3”)]
T3(第3类),
// ...
}

如果这不是一个选项,那么您确实需要创建一个自定义反序列化器。就代码而言,最短的可能是反序列化为,然后匹配
类型
,并将
serde_json::Value
反序列化为正确的
类型{1,2,3}

使用serde_json::Value;
消息的impl{
fn反序列化结果
哪里
S:序列化程序,
{
#[导出(序列化)]
#[塞尔德(未标记)]
枚举消息,
}
让msg=match self{
Message::T1(t)=>TypedMessage{t:1,msg:Message_u216;::T1(t)},
Message::T2(t)=>TypedMessage{t:2,msg:Message_u216;::T2(t)},
Message::T3(t)=>TypedMessage{t:3,msg:Message_u216;::T3(t)},
};
msg.serialize(序列化程序)
}
}

使用时,则使用,这在文档中是隐藏的。您可以使用和
FlatMapSerializer
来代替创建新类型

但是,请注意,鉴于serde没有文档记录,如果您直接使用
FlatMapSerializer
,则任何未来版本的serde都可能会破坏您的代码

使用serde::{private::ser::FlatMapSerializer,ser::SerializeMap,Serializer};
消息的impl序列化{
fn序列化(&self,序列化程序:S)->结果
哪里
S:序列化程序,
{
让mut s=serializer.serialize_-map(无)?;
让类型\=&匹配self{
消息::T1()=>1,
消息::T2()=>2,
消息::T3()=>3,
};
s、 序列化_项(“类型”、&type_)?;
匹配自我{
Message::T1(t)=>t.serialize(FlatMapSerializer(&mut s))?,
消息::T2(t)=>t.serialize(FlatMapSerializer(&mut s))?,
消息::T3(t)=>t.serialize(FlatMapSerializer(&mut s))?,
}
s、 完()
}
}

第二个解决方案就是我一直在寻找的。效果很好。确实需要序列化。非常感谢。