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

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

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

推荐答案

The serialize_with attribute

您可以使用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位的最佳方法").

Implement serde::Serialize

另一种半手动方法是使用自动派生的序列化创建单独的 struct ,并使用以下方法实现序列化:

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

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

Rust相关问答推荐

重新导出proc宏导致未解决的extern crate错误""

如何优化小型固定大小数组中的搜索?

为什么单元类型(空元组)实现了`Extend`trait?

为什么我可以跟踪以前borrow 过的变量?房主在哪里?

是否可以在不切换到下一个位置的情况下获得迭代器值:

为什么这个变量不需要是可变的?

程序在频道RX上挂起

使用 select 处理 SIGINT 和子等待!无阻塞

Rust ECDH 不会产生与 NodeJS/Javascript 和 C 实现相同的共享密钥

返回迭代器考虑静态生命周期类型

缺失serde的字段无法设置为默认值

为什么需要同时为值和引用实现`From`?方法不应该自动解引用或borrow 吗?(2023-06-16)

有什么办法可以追踪泛型的单态化过程吗?

如何刷新 TcpStream

使用 rust 在 google cloud run (docker) 中访问环境变量的适当方法

在 FFI 的上下文中,未初始化是什么意思?

在 RefCell 上borrow

如何为返回正确类型的枚举实现 get 方法?

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?

令人困惑的错误消息? (解包运算符)