Как преобразовать поля при сериализации с помощью Serde?
Как я могу применить преобразование к полю перед сериализацией?
Например, как я могу убедиться, что поля lat
а также lon
в этом определении структуры округляются до 6 знаков после запятой перед сериализацией?
#[derive(Debug, Serialize)]
struct NodeLocation {
#[serde(rename = "nodeId")]
id: u32,
lat: f32,
lon: f32,
}
1 ответ
serialize_with
атрибут
Вы можете использовать serialize_with
атрибут для предоставления настраиваемой функции сериализации для вашего поля:
#[macro_use]
extern crate serde_derive;
extern crate serde;
use serde::Serializer;
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
Другой полуручный подход заключается в создании отдельной структуры с автоматически производной сериализацией и реализации вашей сериализации с использованием этого:
#[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(),
}
}
}
В частности, это позволяет вам также добавлять или удалять поля, поскольку "внутренний" сериализованный тип может делать в основном все, что захочет.