17

シリアル化の前にフィールドに変換を適用するにはどうすればよいですか?

たとえば、シリアル化する前に、この構造体定義内のフィールドが小数点以下 6 桁までに丸められるようにするにはどうすればよいlatでしょlonうか?

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

1 に答える 1

22

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

特に、これにより、「内部」のシリアル化された型は基本的に必要なことを何でもできるため、フィールドを追加または削除することもできます。

于 2016-09-08T12:11:17.940 に答える