Rust中如何将rust_decimal::Decimal类型正确存入MongoDB
rust_decimal存储到MongoDB的正确方式
直接传值报错的核心原因是bson crate默认没有实现针对第三方rust_decimal::Decimal类型的转换trait;直接传字节转换失败是因为两种Decimal类型的内存布局完全不兼容,并非单纯大小端问题:rust_decimal::Decimal内部采用96位尾数+32位标度/符号的自定义布局,而MongoDB使用的bson::Decimal128遵循IEEE 754-2008 Decimal128标准,采用1位符号+14位指数+113位尾数的布局,直接拷贝字节必然得到错误结果。
推荐方案:启用rust_decimal官方bson适配特性
rust_decimal 1.24.0已经内置了对bson 2.x版本的转换支持,只是默认没有开启,只需要在Cargo.toml中开启对应feature即可:
[dependencies] mongodb = "2.2.2" bson = "2.3.0" rust_decimal = { version = "1.24.0", features = ["bson"] }
开启feature后,rust_decimal会自动实现From<Decimal> for Bson的转换trait,最初写的插入代码不需要做任何修改,运行时会自动将值转换为MongoDB原生Decimal128类型存储,全程无精度损失。
手动转换方案:字符串中转
如果不想引入额外feature,可以通过标准十进制字符串作为中转完成转换,bson::Decimal128内置了字符串解析能力,该路径同样不会丢失精度:
// self.db is of type mongodb::sync::Database use bson::Decimal128; use std::str::FromStr; let decimal = Decimal::new(1, 20); let bson_decimal = Decimal128::from_str(&decimal.to_string()) .expect("decimal value exceeds MongoDB Decimal128 valid range"); let order = doc! {"decimal": bson_decimal}; self.db.collection("collection").insert_one(order, None).unwrap();
注意:如果你的Decimal数值超出了IEEE 754 Decimal128的可表示范围,字符串解析会返回错误,需要提前做范围校验,或者选择将值存为字符串/二进制等其他类型。
内容的提问来源于stack exchange,提问作者Dipsy Shrimp
相关产品推荐
相关产品推荐

