簡體   English   中英

Rust 反序列化 JSON 成自定義 HashMap<string, google_firestore1::value></string,>

[英]Rust deserialize JSON into custom HashMap<String, google_firestore1::Value>

我剛開始使用 Rust 並且在反序列化方面遇到了一些麻煩。

我實際上是在嘗試使用來自以下板條箱google_firestore1的 function ProjectDatabaseDocumentCreateDocumentCall 我想填充 struct Document的字段fields 結構的文檔很清楚,它期望一個HashMap<String, google_firestore1::Value>作為一個值。

問題是,如何將 JSON 字符串反序列化為HashMap<String, google_firestore1::Value>

這是我暫時寫的代碼:

extern crate google_firestore1 as firestore1;

use google_firestore1::Document;
use std::collections::HashMap;
use serde_json;

pub fn go() {

  let _my_doc = Document::default();

  let test = "{\"test\":\"test\", \"myarray\": [1]}";

  // Working perfectly fine
  let _working: HashMap<String, serde_json::Value> = serde_json::from_str(test).unwrap();

  // Not working
  let _not_working: HashMap<String, firestore1::Value> = serde_json::from_str(test).unwrap();

  // Later I want to do the following
  // _my_doc.fields = _not_working
}

Obvsiouly 這不起作用,它崩潰並出現以下錯誤。

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: string \"test\", expected struct Value", line: 1, column: 14)', src/firestore.rs:17:85
stack backtrace:

當然,我注意到serde_json::Valuefirestore1::Value不是同一個 Struct。 但是我看了一下源代碼,似乎firestore1::Value正在實現 Deserialize 特征。

那么為什么它不起作用呢? 在這種情況下,我是否需要遍歷第一個 HashMap 並將serde_json::Value反序列化為firestore1::Value 有沒有更清潔的方法來做我想做的事?

感謝您的回答 !

firestore1::Value的定義是:

/// A message that can hold any of the supported value types.
/// 
/// This type is not used in any activity, and only used as *part* of another schema.
/// 
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Value {
    /// A bytes value.
    /// 
    /// Must not exceed 1 MiB - 89 bytes.
    /// Only the first 1,500 bytes are considered by queries.
    #[serde(rename="bytesValue")]
    pub bytes_value: Option<String>,
    /// A timestamp value.
    /// 
    /// Precise only to microseconds. When stored, any additional precision is
    /// rounded down.
    #[serde(rename="timestampValue")]
    pub timestamp_value: Option<String>,

    ...

}

這意味着firestore1::Value的每個條目都必須是 object。 懷疑實際上只會設置一個字段,對應於值的實際類型(因為它們都是可選的)。

所以你的 json 需要是這樣的:

let test = r#"{
  "test":{"stringValue":"test"},
  "myarray": {
     "arrayValue":{"values":[{"integerValue":1}]}
  }
}"#;

這非常難看,所以如果你自己做很多 JSON 來進行 firestore 對話,我可能會寫一些幫助程序來從serde_json::Value轉換為firestore1::Value

它可能看起來像這樣:

fn my_firestore_from_json(v:serde_json::Value) -> firestore1::Value {
  match v {
    serde_json::Value::Null => firestore::Value {
      // I don't know why this is a Option<String>
      null_value: Some("".to_string),
      ..Default::default(),
    },
    serde_json::Value::Bool(b) => firestore::Value {
      bool_value: Some(b),
      ..Default::default(),
    },
    // Implement this
    serde_json::Value::Number(n) => my_firestore_number(n),
    serde_json::Value::String(s) => firestore::Value {
      string_value: Some(s),
      ..Default::default(),
    },
    serde_json::Value::Array(v) => firestore::Value {
      array_value:
        Some(firestore1::ArrayValue{
            values:v.into_iter().map(my_firestore_from_json)
        }),
      ..Default::default(),
    },
    // Implement this
    serde_json::Value::Object(d) => my_firststore_object(/* something */) 
  }
}

如果有針對firestore1::ValueFrom<T>的各種實現,這會更簡潔一些,但是使用Default的實現不會太難看。

還值得注意的是,並不是所有的 firebase 類型都在這里創建,因為 serde_json 表示的類型與 firebase 支持的類型不同。

無論如何,這允許您使用您的 JSON 通過執行以下操作來編寫:

let test = "{\"test\":\"test\", \"myarray\": [1]}";
let working: HashMap<String, serde_json::Value> = serde_json::from_str(test).unwrap();
let value_map: HashMap<String, firestore1::Value> = working.iter().map(|(k,v)| (k, my_firestore_from_json(v)).collect();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM