簡述
標準的 serde_json 序列化器不支持直接對浮點數進行格式化限制。如果將浮點數轉換成字符串,又太low逼。這里重點推薦rust_decimal。
#[derive(Serialize)]
pub struct StockTickRow {datetime: NaiveDateTime,code: String,name: String,#[serde(serialize_with = "serialize_float")]weight: f32,#[serde(serialize_with = "serialize_float")]wnbz: f32,#[serde(serialize_with = "serialize_float")]chgp: f32,
}fn serialize_float<S>(value: &f32, serializer: S) -> Result<S::Ok, S::Error>
whereS: Serializer,
{// 這種方式不行,只能轉換成字符串了// let rounded_value = (value * 100.0).round() / 100.0;// serializer.serialize_f32(rounded_value)let formatted_value = format!("{:.2}", value); // 固定兩位小數serializer.serialize_str(&formatted_value)
}
上面是一開始我采用的方式,用了一天,心中不甘。就發現了rust_decimal。這個魔術師:
#[derive(Serialize, Deserialize)]pub struct StockTickRow {datetime: NaiveDateTime,code: String,name: String,#[serde(serialize_with = "serialize_decimal_two_digits")]weight: Decimal,#[serde(serialize_with = "serialize_decimal_two_digits")]wnbz: Decimal,
}fn serialize_decimal_two_digits<S>(value: &Decimal, serializer: S) -> Result<S::Ok, S::Error>
whereS: serde::Serializer,
{let rounded = value.round_dp(2);let float_value: f64 = rounded.try_into().unwrap_or(0.0); // 嘗試轉換,失敗時返回默認值serializer.serialize_f64(float_value)
}
它能在結果中輸出我們期望的格式:?
{"datetime": "2025-04-30T15:09:01","code": "603019","name": "中科曙光","weight": 1.3,"wnbz": 1.22,"chgp": 1.72,}
如果你需要對Decimal類型進行某種轉換或實現,這是個好的例子,它用在dolphindb數據庫中:
impl FromDolphinScalar for Decimal {fn from_scalar(scalar: &ScalarImpl) -> Option<Self> {match scalar {ScalarImpl::Float(c) => c.into_inner().map(|v| Decimal::from_f32(v).unwrap()),ScalarImpl::Double(c) => c.into_inner().map(|v| Decimal::from_f64(v).unwrap()),_ => None,}}
}
Rust-Decimal 除了輸出json比較方便,它還是高精度金融計算庫,不會在四舍五入時丟失精度 。更多信息自己查吧。