如何在没有中间结构的情况下有效地提取 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())?;
我有 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())?;