如何使用动态字段名称反序列化响应?

How to deserialize response with dynamic field name?

正在尝试反序列化 rust get 请求的响应。以下请求似乎工作正常。但是,我想知道是否有一个很好的方法来模拟 TradeResult。现在它有 XXBTZUSD 硬编码。我希望这是任何类型的一对。尝试在 Trades 结果上使用 HashMap<String, TradeResultTypes> 类型;希望这将允许最后一个 属性 和正在检索的那对,但似乎无法让它工作,除非这对像下面那样被硬编码。

extern crate serde;
#[macro_use]
extern crate serde_derive;
use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resp: Trades = reqwest::blocking::get("https://api.kraken.com/0/public/Trades?pair=XBTUSD")?.json()?;
    println!("{:?}", resp);
    Ok(())
}

#[derive(Debug, Deserialize)]
struct Trades {
    result: TradeResult,
    error:  Vec<u32>,
}

// #[derive(Debug, Deserialize)]
// struct Trades {
//     result: HashMap<String, TradeResultTypes>,
//     error:  Vec<u32>,
// }

#[derive(Debug, Deserialize)]
struct TradeResult {
    last: String,
    XXBTZUSD: TradeData,
}

// (price, volume, time, side, orderType, misc)`
type TradeData = Vec<(String, String, f64, String, String, String)>;

#[derive(Debug, Deserialize)]
enum TradeResultTypes {
    String,
    TradeData,
}

您可以使用 untagged 属性反序列化 StringTradeData:

#[derive(Debug, Deserialize)]
struct Trades {
    result: HashMap<String, TradeResultTypes>,
    error:  Vec<u32>,
}

// (price, volume, time, side, orderType, misc)`
type TradeData = Vec<(String, String, f64, String, String, String)>;

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum TradeResultTypes {
    String (String),
    TradeData (TradeData),
}

这样,serde 将首先尝试反序列化 String。如果有效,它将 return 一个 TradeResultTypes::String。如果它不起作用,它将尝试反序列化一个元组数组。如果可行,它将 return 一个 TradeResultTypes::TradeData,否则它将 return 一个错误。

请注意,您需要告诉 Rust 要存储在 enum 的每个变体中的值的类型。换句话说,当我在 enum 中写 String (String) 时,第一个 String 只是一个标签(由于 untagged 属性,serde 将忽略它),第二个 String 是它应该包含的数据类型。它也适用于:

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum TradeResultTypes {
    Last (String),
    Quotations (TradeData),
}