You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中把未知结构的JSON反序列化为通用数据结构?

Rust中使用serde_json反序列化未知结构的JSON

大多数使用Rust和serde_json进行JSON反序列化的示例,都是将JSON反序列化为已定义struct的已知结构。那能不能把未知结构的JSON文档反序列化为可以处理结构差异的通用Rust数据类型?

我尝试了这段代码:

let filename = "example.json";
let maybe_ifile = std::fs::File::open(filename);

match maybe_ifile {
    Ok(ifile) => {
        let maybe_json_data = serde_json::from_reader::<_, BTreeMap<String, String>>(ifile);

        match maybe_json_data {
            Ok(json_data) => {
                println!("{json_data:?}");
            }

            Err(error) => {
                panic!("{error}")
            }
        }
    }

    Err(error) => {
        panic!("{error}");
    }
}

这段代码只在JSON是字符串键值对时有效,没法处理更通用的结构,显然用BTreeMap<String, String>不是正确的方法。我想要实现运行时/动态类型的灵活性,这在其他语言里可行,想必Rust也有简单的解决方案,只是我还不知道。


解决方案

使用serde_json::Value类型

serde_json内置了Value枚举类型,它可以表示所有合法的JSON值,覆盖了JSON的全部数据类型:

  • Null:对应JSON的null
  • Bool(bool):对应JSON的布尔值
  • Number(Number):对应JSON的数字(整数或浮点数)
  • String(String):对应JSON的字符串
  • Array(Vec<Value>):对应JSON的数组
  • Object(Map<String, Value>):对应JSON的对象

只需要把你的代码中的BTreeMap<String, String>替换成Value,就能处理任意结构的JSON了:

use serde_json::Value;
use std::fs::File;

fn main() {
    let filename = "example.json";
    let ifile = File::open(filename).unwrap();
    
    let json_data: Value = serde_json::from_reader(ifile).unwrap();
    println!("{json_data:?}");
}

(注:示例用unwrap()简化了错误处理,实际项目中建议用match或?来优雅处理错误,避免panic)

访问Value中的数据

因为Value是枚举类型,你可以通过模式匹配来区分并访问不同类型的数据:

match &json_data {
    Value::Null => println!("这是null值"),
    Value::Bool(b) => println!("布尔值: {b}"),
    Value::Number(n) => {
        if n.is_i64() {
            println!("整数: {}", n.as_i64().unwrap());
        } else if n.is_f64() {
            println!("浮点数: {}", n.as_f64().unwrap());
        }
    }
    Value::String(s) => println!("字符串: {s}"),
    Value::Array(arr) => println!("数组,长度: {}", arr.len()),
    Value::Object(obj) => println!("对象,键值对数量: {}", obj.len()),
}

更便捷的访问方式

Value还提供了一系列实用方法来简化数据访问,比如:

  • get("key"):从对象中获取指定键对应的值
  • get(index):从数组中获取指定索引的值
  • as_str():尝试将值转换为字符串类型
  • as_i64():尝试将值转换为整数类型
  • as_array():尝试将值转换为数组引用

示例代码:

// 从对象中获取"name"字段的字符串值
if let Some(name) = json_data.get("name").and_then(Value::as_str) {
    println!("名称: {name}");
}

// 从对象中获取"age"字段的整数值
if let Some(age) = json_data.get("age").and_then(Value::as_i64) {
    println!("年龄: {age}");
}

内容的提问来源于stack exchange,提问作者user2138149

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:52:10