示例说明
from_str 解析整棵 JSON 树要先把全部文本读入并构建完整值——数百万元素的数组内存翻数倍。StreamDeserializer 把反序列化拆成逐元素迭代:每个元素解析完即可使用,坏元素只作废自身不拖垮整批。剥掉外层方括号后,元素流的两种来源(字符串切片与 Reader)共用同一套迭代器。
技术要点
- 逐元素迭代替代整树解析
- 坏元素跳过计数不中断
- from_reader 免全文驻留内存
代码解读
parse_array_items 先剥去数组的外括号得到元素序列,into_iter::
使用建议
真实流式场景配 NDJSON 更自然,此模式适合既定 JSON 数组结构。元素间分隔符要规范——多余逗号或空白会影响迭代器推进。大文件 Reader 来源配 BufReader 提升吞吐。
代码示例
use serde::Deserialize;
use serde_json::Deserializer;
use std::io::Cursor;
#[derive(Debug, Deserialize)]
struct Reading {
sensor: String,
celsius: f32,
}
fn parse_array_items(raw: &str) -> (Vec<Reading>, usize) {
// 逐元素反序列化:坏元素跳过并计数
let mut items = Vec::new();
let mut rejected = 0;
let mut de = Deserializer::from_str(trim_brackets(raw)).into_iter::<Reading>();
while let Some(result) = de.next() {
match result {
Ok(reading) => items.push(reading),
Err(_) => rejected += 1,
}
}
(items, rejected)
}
fn trim_brackets(raw: &str) -> &str {
let trimmed = raw.trim();
let body = trimmed
.strip_prefix('[')
.and_then(|s| s.strip_suffix(']'))
.unwrap_or(trimmed);
body
}
fn main() {
let payload = r#"[
{"sensor":"hall-1","celsius":21.4},
{"sensor":"hall-2","celsius":20.9},
{"sensor":"hall-3","celsius":"not-a-number"},
{"sensor":"hall-4","celsius":22.1}
]"#;
let (items, rejected) = parse_array_items(payload);
for reading in &items {
println!("{} -> {:.1}C", reading.sensor, reading.celsius);
}
println!("parsed: {}, rejected: {}", items.len(), rejected);
// Cursor 演示从 Reader 流式消费同一结构
let cursor = Cursor::new(trim_brackets(payload).as_bytes().to_vec());
let stream = Deserializer::from_reader(cursor).into_iter::<Reading>();
println!("reader-based count: {}", stream.filter_map(|r| r.ok()).count());
}