rust 在`serde_json::Value::Number`中计算数字的小数部分

ha5z0ras  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(118)

我的目标是取一个serde_json::Value::Number,如果它包含的数字表示为一个非整数值,其小数部分为0.0,则将其转换为包含等效整数表示的serde_json::Value::Number
我有下面的片段来尝试这一点:

use serde_json::{Number, Value};

fn trim_trailing_zeros(val: Value) -> Value {
    match val {
        Value::Number(n) => Value::Number({
            match n.as_f64() {
                Some(m) => {
                    if m.fract() == 0.0 {
                        Number::from(m as i64)
                    } else {
                        n
                    }
                }
                _ => n,
            }
        }),
        var => var,
    }
}

字符串
这样做的问题是,如果数字不能准确地转换为f64,就像这个Rust Playground链接所显示的那样,输出不等于输入。这似乎是无法克服的,因为Number的字段是私有的,所以我只能使用这几种方法,其中一种似乎是不可避免的as_f64。其他方法似乎在这个问题中根本没用。
有没有人能想到另一种方法来做到这一点?有没有什么方法可以将Value::Number转换为字符串,并尝试在不损失准确性的情况下解析它?

  • 编辑:* 正如评论中所指出的,在尝试as_f64()之前,首先检查Number是否包含i64f64is_i64()is_f64(),理论上也可能遇到转换问题。
d7v8vwbk

d7v8vwbk1#

一种方法是使用serde_jsonarbitrary_precision特性。该特性将数字存储为字符串,然后您可以自己进行解析:

[dependencies]
serde_json = { version = "*", features = ["arbitrary_precision"] }

个字符
操场

tvz2xvvm

tvz2xvvm2#

如果你想不丢失浮点数,你应该考虑使用rust_decimal::Decimal

struct Item {
    name: String,
    price: Decimal,
}

字符串
然后从

let data = r#"
        {
            "name": "Apple",
            "price": "2.99"
        }"#;

let item: Item = serde_json::from_str(data)?;


然后,您可以使用.is_integer区分整数和非整数,在使用.round.fract()(或其他一些,如floorceil,取决于您的规则)进行数字化后,将分数部分和整数部分分开。

相关问题