【问题标题】:How to make serde deserialize BigInt as u64?如何使 serde 将 BigInt 反序列化为 u64?
【发布时间】:2020-03-13 13:27:37
【问题描述】:

我正在使用 tomlnum-bigint 以及 serde 功能来反序列化以下数据:

[[trades]]
action = "Buy"
date_time = 2019-04-15T15:36:00+01:00
fee = [1, [44000000]]
id = "#1"
price = [-1, [20154500000]]
quantity = [1, [200000000]]

但是我收到了这个错误:

Error: Error { inner: ErrorInner { kind: Custom, line: Some(7), col: 14, at: Some(156), message: "invalid value: integer `20154500000`, expected u32", key: ["trades", "price"] } }

当然,如果我使价格值小于u32::MAX,程序编译得很好。但我想使用这个高值,因为我将数字缩放 1e8 以避免处理浮点运算。

是否可以让 serde 将 BigInts 反序列化为 u64

use num_bigint::BigInt;
use serde_derive::Deserialize;
use toml::from_str;
use toml::value::Datetime;

#[derive(Debug, Deserialize)]
pub struct Trade {
    pub action: String,
    pub date_time: Datetime,
    pub fee: BigInt,
    pub id: Option<String>,
    pub price: BigInt,
    pub quantity: BigInt,
}

#[derive(Debug, Deserialize)]
pub struct TradeTable {
    pub trades: Vec<Trade>,
}

fn main() {
    let trades_string: String = String::from("[[trades]]\naction = \"Buy\"\ndate_time = 2019-04-15T15:36:00+01:00\nexchange = \"Degiro\"\nfee = [1, [44000000]]\nid = \"#1\"\nprice = [-1, [20154500000]]\nquantity = [1, [200000000]]");
    let trade_table: TradeTable = from_str(&trades_string).unwrap();
    let trades: Vec<Trade> = trade_table.trades;
}

Also, here's a link to a Rust Playground。请注意,您需要将代码复制到本地计算机,因为您需要来自 num-bigintserde 功能:

Cargo.toml

[dependencies.num-bigint]
version = "0.2.6"
features = ["serde"]

【问题讨论】:

  • 你是如何反序列化数据的?您能否提供一些示例代码?有多种方法可以反序列化这个 toml 片段,如果您向我们展示您在做什么,我们只能告诉您您的方法有什么问题。
  • Toml 文件中的数据不是BigInt,它只是文本。如果需要,您可以尝试将其反序列化为 BigInt,但这仅在您使用预期格式时才有效。你是如何创建这个文件的——你是通过序列化 BigInt 来创建的,还是手动编写的?
  • 对不起,让我用 Rust 操场的链接更新问题正文
  • @trentcl 我是手写数据的。
  • @Paul 感谢您的更新。请务必在问题本身中包含代码以及链接到它。我是否正确假设大多数示例都是无关紧要的,并且仅使用这一行就会出现相同的错误:let price: BigInt = toml::from_str("[-1, [20154500000]]").unwrap();? (我目前无法在本地测试。)

标签: rust deserialization serde toml


【解决方案1】:

你是如何创建这个文件的——你是通过序列化 BigInt 来创建的,还是手动编写的?

我手写的数据。

您的数据无效,以下工作:

use num_bigint::BigInt;
use std::str::FromStr;

#[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq)]
pub struct Trade {
    pub price: BigInt,
}

fn main() {
    let price = BigInt::from_str("-201545000000000").unwrap();
    let trade = Trade { price };

    let j = serde_json::to_string(&trade).unwrap();
    println!("{}", j);
    let a: Trade = serde_json::from_str(&j).unwrap();
    assert_eq!(trade, a);

    let j = toml::to_string(&trade).unwrap();
    println!("{}", j);
    let b: Trade = toml::from_str(&j).unwrap();
    assert_eq!(trade, b);
}

您不应该手动创建它。

【讨论】:

  • 好吧,我正在编写一个 Rust 程序供我自己使用。为什么我们不应该创建或提供我们自己的 toml 文件?
  • @PaulRazvanBerg 很好地将它存储为字符串。这并不意味着要在生锈之外使用。 bigint 的格式没有指定所以...(或者我错过了)
  • @Paul 你可以提供你自己的 toml 文件,但是如果你想将它反序列化为一个BigInt,它必须包含一个有效的BigInt,对吧?我的意思是,您不会期望"hello, world" 能够成功反序列化为BigInt,那么为什么要[-1, [20154500000]]?如果您想知道在 Toml 文件中将-20154500000 表示为BigInt 的正确方法,我建议将其序列化(就像 Stargateur 的程序一样)并查看结果。
  • 是的 20154500000 序列化形式似乎是 [1, [2974630816, 4]]。我将尝试为我的问题找到替代解决方案。谢谢你们的帮助!
猜你喜欢
  • 2023-02-22
  • 1970-01-01
  • 2020-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
  • 1970-01-01
相关资源
最近更新 更多