如何使用 Serde 在序列化期间转换字段?

Posted

技术标签:

【中文标题】如何使用 Serde 在序列化期间转换字段?【英文标题】:How to transform fields during serialization using Serde? 【发布时间】:2020-03-16 09:55:23 【问题描述】:

如何在序列化之前对字段应用转换?

例如,如何确保此结构定义中的字段latlon 在被序列化之前最多四舍五入到小数点后6 位?

#[derive(Debug, Serialize)]
struct NodeLocation 
    #[serde(rename = "nodeId")]
    id: u32,
    lat: f32,
    lon: f32,

【问题讨论】:

手动实现Serialize? 【参考方案1】:

serialize_with 属性

您可以使用serialize_with attribute 为您的领域提供a custom serialization function:

use serde::Serialize, Serializer; // 1.0.104

fn round_serialize<S>(x: &f32, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,

    s.serialize_f32(x.round())


#[derive(Debug, Serialize)]
pub struct NodeLocation 
    #[serde(rename = "nodeId")]
    id: u32,
    #[serde(serialize_with = "round_serialize")]
    lat: f32,
    #[serde(serialize_with = "round_serialize")]
    lon: f32,

(我已经四舍五入到最接近的整数以避免主题“将浮点数四舍五入到 k 位小数的最佳方法”)。

实现serde::Serialize

另一种半手动的方法是使用自动派生的序列化创建一个单独的结构,并使用它来实现您的序列化:

use serde::Serialize, Serializer; // 1.0.104

#[derive(Debug)]
pub struct NodeLocation 
    id: u32,
    lat: f32,
    lon: f32,


impl serde::Serialize for NodeLocation 
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    
        // Implement your preprocessing in `from`.
        RoundedNodeLocation::from(self).serialize(s)
    


#[derive(Debug, Serialize)]
pub struct RoundedNodeLocation 
    #[serde(rename = "nodeId")]
    id: u32,
    lat: f32,
    lon: f32,


impl<'a> From<&'a NodeLocation> for RoundedNodeLocation 
    fn from(other: &'a NodeLocation) -> Self 
        Self 
            id: other.id,
            lat: other.lat.round(),
            lon: other.lon.round(),
        
    

值得注意的是,这还允许您添加或删除字段,因为“内部”序列化类型基本上可以做任何它想做的事情。

【讨论】:

以上是关于如何使用 Serde 在序列化期间转换字段?的主要内容,如果未能解决你的问题,请参考以下文章

使用serde-xml-rs反序列化XML会创建Err(重复字段`$ value`)

Hive 如何存储数据,啥是 SerDe?

如何在序列化期间隐藏字段(但不是反序列化)

HIVE Row Formats和SerDe

Hive系列之SerDe

如果值为空,如何告诉杰克逊在序列化期间忽略一个字段?