2

serde_json を使用して json ドキュメントを逆シリアル化しています。文字列(これはjsonドキュメントです)を指定すると、serde_json値(これはjsonタイプを表す列挙型)を返し、オプションを返す関数があります。この値は、必要に応じて他の関数に渡されます。

ただし、値を渡すことは、私が望んでいるものではないことに気付きました。これを行うと、キーが利用できないためです。

私の要点を説明するために、次のような json ドキュメントがあるとします。

{
  "root" : {
    "regex" : null,
    "prefixes" : [ "a_", "b_" ]
  }
}

"root" は json オブジェクト、"regex" は json Null、"prefixes" は json 配列です。

ここで、json 型の Value は、json 型を表す識別子を持つ列挙型です。たとえば、上記の例では Object、Null、Array です。

serde_json クレートは std::collections::BTreeMap を使用して json ドキュメント内のノードを表し、String 型は json キーを表します (上記では、これらは「ルート」、「正規表現」、および「プレフィックス」になります。 Values への参照だけでは部分的にしか役に立ちません。キーにもアクセスできるように、代わりに BTreeMap を渡す必要があります。

したがって、これは私が書き直そうとしている次の関数です。

fn get_json_content(content_s : &str) -> Option<Value> {
    // instead of returning a value, we need to return a BTreeMap, so we can get the
    // key and the value.
    println!("===>>> json_content obtained: {}", content_s);

    match serde_json::from_str(content_s) { // -> Result<Value>
        Ok(some_value) => Some(some_value),
        Err(_) => None
    }    
}

そのため、関数を書き直し始めましたが、「この値の型は、このコンテキストで既知である必要があります」というエラーに直面しました。

fn get_json_content_as_btreemap<'a>(content_s : &str) -> Option<&'a BTreeMap<String, Value>> {
    match serde_json::from_str(content_s) { // -> Result<Value>
        Ok(some) => {
            // I expect the type of key_value_pair to be BTreeMap<String, Value>>
            // (but I may be wrong!)
            let key_value_pair = some.as_object().unwrap(); // Error here

        },
        Err(_) => None
    }
}

このようなスタックオーバーフローに関する他の質問を見つけました: この値のタイプは、このコンテキストで既知である必要があります

これをヘルパーとして使用して、次のように型を挿入しようとしました:

let key_value_pair = some.as_object::<BTreeMap<_, _>>().unwrap();

これは問題を解決しません。また、他の同様のバリエーションを試してみましたが、役に立ちませんでした。では、どうすればこれを修正できますか?

編集:

このアプリには次のような別の機能があります。

fn get_root_value<'a>(json_documemt : &'a Value) -> Result<&'a Value, JsonErrorCode> {
    if json_documemt.is_object() {
        for (k, v) in json_documemt.as_object().unwrap().iter() {
            if k == "root" {
                println!("found root: {}",  k);

                return Ok(v)
            }
        }

        return Err(JsonErrorCode::Custom("Failed to find root node".to_string()))
    }

    Err(JsonErrorCode::Custom("Not an object".to_string()))
}

...そしてこれはうまくいきます。ここでは、as_object() を呼び出して、キーと値をタプル ペアとして取得できることがわかります。as_object があるケースでは機能しているのに、別のケースでは機能していない理由がわかりません。BTreeMap を取り出して、これを借用アイテムとして渡したいと思います。

4

1 に答える 1

0

初期関数の戻り値の型を変更できます。次のserde_jsonことが可能であれば、適切なオブジェクトに逆シリアル化されます。

fn get_json_content(content_s : &str) -> Option<BTreeMap<String, Value>> {
    // instead of returning a value, we need to return a BTreeMap, so we can get the
    // key and the value.
    println!("===>>> json_content obtained: {}", content_s);

    match serde_json::from_str(content_s) { // -> Result<Value>
        Ok(some_value) => Some(some_value),
        Err(_) => None
    }    
    // Note: this match statement can be rewritten as
    // serde_json::from_str(content_s).ok()
}

Value関数内でオブジェクトをインスタンス化し、インスタンス化したばかりのオブジェクトへの参照を返そうとしているため、2 番目の例は機能しません。関数の最後でオブジェクトがスコープ外になり、参照が無効になるため、これは機能しません。

于 2016-05-25T15:18:55.257 に答える