シリアル化の前にフィールドに変換を適用するにはどうすればよいですか?
たとえば、シリアル化する前に、この構造体定義内のフィールドが小数点以下 6 桁までに丸められるようにするにはどうすればよいlat
でしょlon
うか?
#[derive(Debug, Serialize)]
struct NodeLocation {
#[serde(rename = "nodeId")]
id: u32,
lat: f32,
lon: f32,
}
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
もう 1 つの半手動のアプローチは、自動派生シリアル化を使用して別の構造体を作成し、それを使用してシリアル化を実装することです。
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(),
}
}
}
特に、これにより、「内部」のシリアル化された型は基本的に必要なことを何でもできるため、フィールドを追加または削除することもできます。