问题
How can I apply a transformation to a field before serialization?
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,
}
回答1:
The serialize_with
attribute
You can use the serialize_with attribute to provide a custom serialization function for your field:
#[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,
}
(I've rounded to the nearest integer to avoid the topic "what is best way to round a float to k decimal places").
Implement serde::Serialize
The other semi-manual approach is to create a separate struct with auto-derived serialization, and implement your serialization using that:
#[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.
来源:https://stackoverflow.com/questions/39383809/how-to-transform-fields-during-serialization-using-serde