我想chrono::NaiveDate
使用自定义函数序列化和反序列化,但Serde书籍不包含此功能,代码文档也没有帮助.
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate chrono;
use chrono::NaiveDate;
mod date_serde {
use chrono::NaiveDate;
use serde::{self, Deserialize, Serializer, Deserializer};
pub fn serialize<S>(date: &Option<NaiveDate>, s: S) -> Result<S::Ok, S::Error>
where S: Serializer {
if let Some(ref d) = *date {
return s.serialize_str(&d.format("%Y-%m-%d").to_string())
}
s.serialize_none()
}
pub fn deserialize<'de, D>(deserializer: D)
-> Result<Option<NaiveDate>, D::Error>
where D: Deserializer<'de> {
let s: Option<String> = Option::deserialize(deserializer)?;
if let Some(s) = s {
return Ok(Some(NaiveDate::parse_from_str(&s, "%Y-%m-%d").map_err(serde::de::Error::custom)?))
} …
Run Code Online (Sandbox Code Playgroud) 我有一个JSON对象,其中包含一些元数据键和一个大数据有效负载.我的服务关注用于记录和路由的元数据,但不关心有效负载,而是将有效负载传递给另一个服务.我永远不需要出于任何原因查看有效载荷.
现在,有效负载在我的结构中表示为serde_json::Value
.通过剖析,我已经看到(de)序列化Value
需要花费大量的时间.
在Serde中是否有一种机制可以捆绑有效负载而无需支付将其反序列化为组件值的成本,只是需要在以后重新序列化它们?
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[derive(Serialize, Deserialize)]
struct DataBlob<'a> {
id: &'a str,
priority: u8,
// payload: OpaqueValue,
}
fn main() {
let input = r#"{
"id": "cat",
"priority": 42,
"payload": [1, 2, 3, 4]
}"#;
let parsed = serde_json::from_str::<DataBlob>(input).expect("Could not deserialize");
let output = serde_json::to_string(&parsed).expect("Could not serialize");
assert!(output.contains("payload"));
}
Run Code Online (Sandbox Code Playgroud) 我试图弄清楚如何使用Serde将JSON反序列化为结构.例如,serde_json 自己的文档中的示例JSON 包含以下数据:
{
"FirstName": "John",
"LastName": "Doe",
"Age": 43,
"Address": {
"Street": "Downing Street 10",
"City": "London",
"Country": "Great Britain"
},
"PhoneNumbers": [
"+44 1234567",
"+44 2345678"
]
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我们假设上面的数据是在变量"input"和下面的代码中:
let deserialized_data: Data = serde_json::from_str(input).unwrap();
Run Code Online (Sandbox Code Playgroud)
......结构应该是什么Data
样的?
使用serde_json箱子,我可以使用
::serde_json::to_string(&obj)
Run Code Online (Sandbox Code Playgroud)
将对象序列化为JSON字符串.生成的JSON使用紧凑格式,如:
{"foo":1,"bar":2}
Run Code Online (Sandbox Code Playgroud)
但是如何生成漂亮/缩进的JSON?例如,我想得到这个:
{
"foo": 1,
"bar": 2
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试解决序列化和反序列化的问题Box<SomeTrait>
.我知道在封闭类型层次结构的情况下,推荐的方法是使用枚举,并且序列化没有问题,但在我的情况下使用枚举是不合适的解决方案.
起初我尝试使用Serde,因为它是事实上的Rust序列化机制.Serde能够序列化Box<X>
但不能在何时X
成为特征.该Serialize
特性不能为特征的对象实现的,因为它具有通用的方法.这个特殊问题可以通过使用擦除serde来解决,因此序列化Box<SomeTrait>
可以工作.
主要问题是反序列化.要反序列化多态类型,您需要在序列化数据中使用某种类型标记.该标记应首先反序列化,然后用于动态获取将返回的函数Box<SomeTrait>
.
std::any::TypeId
可以用作标记类型,但主要问题是如何动态获取反序列化函数.我不考虑为应用程序初始化期间应手动调用的每种多态类型注册函数的选项.
我知道有两种可能的方法:
但Rust中没有这些选项.如果有的话,如何在Rust中添加多态对象的反序列化?
对于上下文:我正在用 Rust 编写光线追踪器,但我正在努力寻找一种以与文件系统无关的方式加载场景的好方法。我正在使用serde,这样我就不必发明自己的文件格式(还)。资源(图像纹理和网格数据)单独存储到场景文件中。场景文件只存储这些文件的路径。因为光线追踪器本身应该是一个与平台无关的库(我希望能够将其编译为浏览器的 WebAssembly),所以光线追踪器本身不了解文件系统。我打算在反序列化场景时加载资产,但这现在给我带来了真正的问题:
我需要将文件系统接口代码的实现传递给我可以使用的 serde Deserialize::deserialize()
,但似乎没有任何简单的方法可以做到这一点。我想出了一种使用泛型来实现这一点的方法,但我对此并不满意。
这是我目前正在做的方式,作为 MCVE 进行剥离(使用的包是serde
和serde_json
):
库代码(lib.rs):
use std::marker::PhantomData;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
pub struct Image {}
pub struct Texture<L: AssetLoader> {
path: String,
image: Image,
phantom: PhantomData<L>,
}
impl<L: AssetLoader> Serialize for Texture<L> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.path.serialize(serializer)
}
}
impl<'de, L: AssetLoader> Deserialize<'de> for Texture<L> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Texture<L>, D::Error> {
let path = String::deserialize(deserializer)?;
// This …
Run Code Online (Sandbox Code Playgroud) 我有一个关于特定情况下的内存分配策略的问题。
我有大量的结构体通过 serde 来自 JSON API。JSON 响应中有一个特定字段,在少数情况下,该字段将存在并包含恰好包含 11 个元素的数组。在大多数情况下,该字段在响应中根本不存在。所有响应都需要存储。
大多数回复的格式如下:
{
id: 1,
event: "None"
}
Run Code Online (Sandbox Code Playgroud)
少数回复将采用以下格式:
{
id: 2,
event: "something",
event_details : [11 json objects here]
}
Run Code Online (Sandbox Code Playgroud)
如果我将用于解析 JSON 的结构定义为:
#[derive(Deserialize, Debug)]
struct Event {
id: u32,
event: String,
// EventDetail is a struct with an u32 and string field
events: Option<[EventDetail; 11]>
}
Run Code Online (Sandbox Code Playgroud)
我可以看到使用deepsizeof crateVec<Event>
创建的文件占用了约 500MB 的内存。如果我将该events
字段更改为,events: Option<Box<[EventDetail; 11]>>
内存使用量会下降到约 150MB。
我的理解是,由于 Box 是在运行时而不是编译时分配的,因此当传入的 JSON 响应缺少该字段时events
,则不需要分配 11 项数组。我在这里说得对吗?这是 Box …
如何在序列化之前将转换应用于字段?
例如,如何确保字段lat
和lon
此结构定义在序列化之前舍入到最多6个小数位?
#[derive(Debug, Serialize)]
struct NodeLocation {
#[serde(rename = "nodeId")]
id: u32,
lat: f32,
lon: f32,
}
Run Code Online (Sandbox Code Playgroud) 在程序开始时,我从文件中读取数据:
let file = std::fs::File::open("data/games.json").unwrap();
let data: Games = serde_json::from_reader(file).unwrap();
Run Code Online (Sandbox Code Playgroud)
我想知道如何在编译时执行此操作,原因如下:
我可能还需要提到的是,数据只能读取,这意味着解决方案可以将其存储为静态。
我正在尝试获取枚举变体的名称,作为字符串 serde 期望/创建的名称。例如,假设我有以下枚举:
#[derive(Serialize, Deserialize)]
#[serde(rename_all="camelCase")]
pub enum SomeEnum {
WithoutValue,
withValue(i32),
}
Run Code Online (Sandbox Code Playgroud)
那么我怎样才能获得变体的 serde 名称呢?就像是
serde::key_name(SomeEnum::WithoutValue) // should be `withoutValue`
serde::key_name(SomeEnum::WithValue) // should be `withValue`
Run Code Online (Sandbox Code Playgroud)
serde_json
对于没有值的变体,我可以使用 , 进行黑客攻击:
serde_json::to_string(SomeEnum::WithoutValue).unwrap(); // yields `"withoutValue"` with quotation marks
Run Code Online (Sandbox Code Playgroud)
这不是最好的解决方案,因为我需要去掉引号,但在技术上可以工作。
更糟糕的是当枚举变量具有值时。它变得更加混乱。
serde_json::to_string(SomeEnum::WithValue(0)).unwrap(); // yields `"{\"second\":0}"
Run Code Online (Sandbox Code Playgroud)
有没有一种干净的方法来实现这一目标?我找不到 serde API 来获取字符串形式的键名。