Как преобразовать поля во время сериализации с помощью Serde?

Как я могу применить преобразование к полю перед сериализацией?

Например, как я могу гарантировать, что поля lat и lon в этом определении структуры округлены не более чем до 6 знаков после запятой перед сериализацией?

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

person Synesso    schedule 08.09.2016    source источник
comment
Внедрить вручную Serialize?   -  person Kroltan    schedule 08.09.2016


Ответы (1)


Атрибут 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(),
        }
    }
}

Примечательно, что это позволяет вам также добавлять или удалять поля, поскольку «внутренний» сериализованный тип может делать практически все, что захочет.

person krdln    schedule 08.09.2016