我有一个JSON,它返回的对象如下所示:
{
"PrivatePort": 2222,
"PublicPort": 3333,
"Type": "tcp"
}为了捕捉到这一点,我有一个枚举和一个结构:
#[derive(Eq, PartialEq, Deserialize, Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum PortType {
Sctp,
Tcp,
Udp,
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct PortMapping {
pub private_port: u16,
pub public_port: u16,
#[serde(rename = "Type")]
pub port_type: PortType,
}现在,这个API只支持PortType中列出的三种协议,但让我们假设将来会增加对DCCP的支持。我不希望API的客户端因为配置选项中的一个未知字符串而开始失败。
为了解决这个问题,我添加了一个Unknown变体和一个String来表示值:
#[derive(Eq, PartialEq, Deserialize, Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum PortType {
Sctp,
Tcp,
Udp,
Unknown(String),
}这里的目标是在传入未知值时得到稍微不方便的PortType::Unknown("dccp")值。当然,这样做不会像我想要的那样--传递未知的"dccp"值将导致:
Error("unknown variant `dccp`, expected one of `sctp`, `tcp`, `udp`, `unknown`", line: 1, column: 55)是否有用于做我想做的事情的Serde配置,或者是否应该手动为Deserialize和Serialize实现编写PortType
发布于 2019-08-13 10:09:14
简单的情况应该是这样的:
use serde::de::Visitor;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::from_str;
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct PortMapping {
pub private_port: u16,
pub public_port: u16,
#[serde(rename = "Type")]
pub port_type: PortType,
}
#[derive(Clone, Eq, PartialEq, Serialize, Debug)]
pub enum PortType {
Sctp,
Tcp,
Udp,
Unknown(String),
}
const PORT_TYPE: &'static [(&'static str, PortType)] = &[
("sctp", PortType::Sctp),
("tcp", PortType::Tcp),
("udp", PortType::Udp),
];
impl From<String> for PortType {
fn from(variant: String) -> Self {
PORT_TYPE
.iter()
.find(|(id, _)| *id == &*variant)
.map(|(_, port_type)| port_type.clone())
.unwrap_or(PortType::Unknown(variant))
}
}
impl<'a> From<&'a str> for PortType {
fn from(variant: &'a str) -> Self {
PORT_TYPE
.iter()
.find(|(id, _)| *id == &*variant)
.map(|(_, port_type)| port_type.clone())
.unwrap_or_else(|| PortType::Unknown(variant.to_string()))
}
}
impl<'de> Deserialize<'de> for PortType {
fn deserialize<D>(de: D) -> Result<PortType, D::Error>
where
D: Deserializer<'de>,
{
struct PortTypeVisitor {}
impl<'de> Visitor<'de> for PortTypeVisitor {
type Value = PortType;
fn expecting(
&self,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::result::Result<(), std::fmt::Error> {
fmt.write_str("We expected a string")
}
fn visit_str<E>(self, variant: &str) -> Result<Self::Value, E> {
Ok(variant.into())
}
fn visit_string<E>(self, variant: String) -> Result<Self::Value, E> {
Ok(variant.into())
}
}
de.deserialize_string(PortTypeVisitor {})
}
}
fn main() {
let input = r#"
{
"PrivatePort": 2222,
"PublicPort": 3333,
"Type": "dccp"
}
"#;
let result: Result<PortMapping, _> = from_str(input);
println!("{:#?}", result);
}我不认为有一种惯用的方法来做到这一点,这可能会被包括在未来。
发布于 2020-09-20 02:41:17
这是一个问题,尽管它已经开放了3年,至今还没有完全解决问题。塞德#912。
在撰写这篇文章时,似乎正在实现(尽管没有文档)的是#[serde(other)]。它只能应用于单位枚举字段,这限制了它的用途:
#[derive(Deserialize, PartialEq)]
#[serde(tag = "tag")]
enum Target {
A(()),
B(()),
#[serde(other)]
Others
}
fn main() {
assert_eq!(Target::Others, from_str::<Target>(r#"{ "tag": "blablah" }"#).unwrap());
}除此之外,撰写本文时唯一的其他方法是编写您自己的Deserialize实现。
发布于 2020-12-12 15:51:55
我是用serde(from="String")来做的
#[derive(Eq, PartialEq, Deserialize, Serialize, Debug)]
#[serde(rename_all = "snake_case", from="String")]
pub enum PortType {
Sctp,
Tcp,
Udp,
Unknown(String),
}
impl From<String> for PortType {
fn from(s: String)->Self {
use PortType::*;
return match s.as_str() {
"sctp" => Sctp,
"tcp" => Tcp,
"udp" => Udp,
_ => Unknown(s)
}
}
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct PortMapping {
pub private_port: u16,
pub public_port: u16,
#[serde(rename = "Type")]
pub port_type: PortType,
}https://stackoverflow.com/questions/57469527
复制相似问题