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

26

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

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

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

1
需要手动实现 Serialize 吗? - Kroltan
1个回答

40

serialize_with属性

您可以使用serialize_with属性为字段提供自定义序列化函数

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(),
        }
    }
}

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接