如何在没有中间结构的情况下有效地提取 JSON 的一部分作为 Vec?

How to efficiently extract a portion of JSON as a Vec without intermediate structs?

我有 JSON 内容,其中嵌套很深,有一组我要提取的数字。我不想创建中间结构,所以我尝试了以下操作:

... get f
let json = serde_json::from_reader::<_, serde_json::Value>(f)?;
let xs: Vec<(f64, f64)> = serde_json::from_value(json["subtree"][0])?;

这抱怨

11 | serde_json::from_value(json["subtree"][0])?;
   |                        ^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `serde_json::value::Value`, which does not implement the `Copy` trait

如果我 clone,它工作正常:

let xs: Vec<(f64, f64)> = serde_json::from_value(json["subtree"][0].clone())?;

但这似乎没有必要。我不会使用结构的其余部分。如何在无需创建中间结构且无需克隆的情况下实现此目的?

我可能会使用 Value::pointer。一个例子:

use serde_json::json;

fn main() {
    let value = json!({
        "deeply": {
            "nested": {
                "array": [0, 1, 2, 3, 4, 5]
            }
        }
    });

    let numbers: Vec<u64> = value
        .pointer("/deeply/nested/array")
        .unwrap()
        .as_array()
        .unwrap()
        .iter()
        .map(|x| x.as_u64().unwrap())
        .collect();

    println!("{:?}", numbers);
}

注意:此示例包含过度使用 unwrap() 调用 很危险,会导致恐慌。它的存在是为了让整个 例子更简单。


Aren’t you still constructing multiple vectors in this case?

没有。让我们扩展整个机器。

use serde_json::{json, Value};
use std::iter::Map;
use std::slice::Iter;

fn main() {
    let value: Value = json!({
        "deeply": {
            "nested": {
                "array": [0, 1, 2, 3, 4, 5]
            }
        }
    });

    // Option<&Value> - Option & reference
    //
    //    pub enum Option<T> {
    //        None,
    //        Some(T),
    //    }
    //
    // T = &Value - reference
    let maybe_value_ref: Option<&Value> = value.pointer("/deeply/nested/array");

    // &Value - reference
    let value_ref: &Value = maybe_value_ref.unwrap();

    // Option<&Vec<Value>> - Option & reference
    //
    //    pub enum Option<T> {
    //        None,
    //        Some(T),
    //    }
    //
    // T = &Vec<Value> - reference to Vec
    let maybe_vec_ref: Option<&Vec<Value>> = value_ref.as_array();

    // &Vec<Value> - reference
    let vec_ref: &Vec<Value> = maybe_vec_ref.unwrap();

    // Iter<Value> allocation
    //
    //    pub struct Iter<'a, T: 'a> {
    //        ptr: *const T,
    //        end: *const T,
    //        _marker: marker::PhantomData<&'a T>,
    //    }
    //
    // .next() returns Option<&Value>
    let vec_ref_iter: Iter<Value> = vec_ref.iter();

    // Map<..., ...> allocation
    //
    //    pub struct Map<I, F> {
    //        iter: I,
    //        f: F,
    //    }
    //
    // .next() returns Option<u64>
    let vec_ref_iter_map: Map<Iter<Value>, fn(&Value) -> u64> =
        vec_ref_iter.map(|x: &Value| x.as_u64().unwrap());

    // Nothing happens till this point. I mean, only Iter, Map, ... structures
    // were allocated. But because they're lazy, we have to consume the last
    // Map (vec_ref_iter_map) to fire the whole machinery.
    //
    // What's going on (simplified)?
    //
    // * Vec implements FromIterator
    // * vec_ref_iter_map implements Iterator
    // * FromIterator consumes vec_ref_iter_map.next() till None (= end)
    // * vec_ref_iter_map.next() returns Option<u64>
    //   * it internally gets vec_ref_iter.next() value
    //   * if value is None then None is returned (= end)
    //   * if value is Some(x) then it applies .map() closure (x.as_u64().unwrap())
    //     and returns Some(closure result)
    //
    // The only allocated Vec here is the last one (numbers). No other Vectors
    // were allocated.
    let numbers: Vec<u64> = vec_ref_iter_map.collect();

    println!("{:?}", numbers);
}

文档:

哦,错过了非常明显的地方。

... get f
let mut json = serde_json::from_reader::<_, serde_json::Value>(f)?;
let xs: Vec<(f64, f64)> = serde_json::from_value(json["subtree"][0].take())?;