如何使用 Serde 在序列化期间转换字段? [英] How to transform fields during serialization using Serde?

查看:13
本文介绍了如何使用 Serde 在序列化期间转换字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How can I apply a transformation to a field before serialization?

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

For example, how can I ensure that the fields lat and lon in this struct definition are rounded to at most 6 decimal places before being serialized?

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

推荐答案

serialize_with 属性

您可以使用serialize_with 属性来提供<一个 href="https://serde.rs/impl-serialize.html" rel="noreferrer">自定义序列化函数,适用于您的领域:

The serialize_with attribute

You can use the serialize_with attribute to provide a custom serialization function for your field:

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 个小数位的最佳方法").

(I've rounded to the nearest integer to avoid the topic "what is best way to round a float to k decimal places").

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

The other semi-manual approach is to create a separate struct with auto-derived serialization, and implement your serialization using that:

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

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

Notably, this allows you to also add or remove fields as the "inner" serialized type can do basically whatever it wants.

这篇关于如何使用 Serde 在序列化期间转换字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆