Rust 中如何解析 JSON?

news2024/12/26 11:33:19

Rust 中如何解析 JSON?

在这里插入图片描述

在本文中,我们将讨论如何在 Rust 中使用 JSON 解析库,以及比较最流行的库及其性能。

JSON 解析基础知识

手动解析 JSON

要开始在 Rust 中使用 JSON,您需要安装一个可以轻松操作 JSON 的库。目前可用的流行crate之一是 serde-json 。您可以通过运行以下命令来安装它:

cargo add serde-json

完成后,您可以像这样手动创建 JSON:

use serde_json::{Result, Value};

fn untyped_example() -> Result<()> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#" {"name":"John Doe", "age": 43, "phones": ["+44 1234567",       "+44 2345678"            ]        }"#;

    // Parse the string of data into serde_json::Value.
    let v: Value = serde_json::from_str(data)?;

    // Access parts of the data by indexing with square brackets.
    println!("Please call {} at the number {}", v["name"], v["phones"][0]);

    Ok(())
}

然而,我们可以做得更好。例如,可以将结构 序列化为 JSON 与 或反序列化,这很常用。我们可以在 JSON 模板、Web 服务、CLI 参数等中使用它。在下一节中完成这一点。

使用 Serde 解析 JSON

Serde 是一个crate,可以帮助您将数据序列化和反序列化为各种格式,其中一个流行的用途是用于 JSON。如果您使用 Rust 编写 Web 服务,Serde 是您的朋友,因为您将经常处理可能需要发送或接收的 JSON 数据。 Serde 提供了两个主要traits来帮助您实现此目的: SerializeDeserialize 。为了方便起见,添加了派生宏实现来帮助解决此问题。请参阅下文了解如何执行此操作:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct MyStruct {
    message: String
}

fn convert_json_to_struct() {
    // create a raw JSON string from the json! macro and turn it into a MyStruct struct
    let raw_json_string = json!({"message": "Hello world!"});
    let my_struct: MyStruct = serde_json::from_str(raw_json_string).unwrap();
}

您还可以通过添加实现 SerializeDeserialize 的结构作为另一个也实现 SerializeDeserialize

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct Post {
      nested_json: PostMetadata,
    title: String,
      body: String
}

#[derive(Serialize, Deserialize)]
pub struct PostMetadata {
      timestamp_created: DateTime<Utc>,
    timestamp_last_updated: Datetime<Utc>,
      categories: Vec<String>,
}

一种用例是将 JSON 嵌套在 Web 服务中。例如,当您收到对具有 JSON 正文的 API 的 POST 请求时,您通常会将相关的 Json 类型作为处理函数参数传递。见下文:

use axum::Json;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct Post {
      nested_json: PostMetadata,
    title: String,
      body: String
}

#[derive(Serialize, Deserialize)]
pub struct PostMetadata {
      timestamp_created: DateTime<Utc>,
    timestamp_last_updated: Datetime<Utc>,
      categories: Vec<String>,
}

async fn receive_some_json(
  // this extractor consumes a JSON body and converts it into the struct type given
    Json(json): Json<Post>
) -> Json<Post> {
  println!("{:?}", json);
    Json(json)
}

除了前面显示如何使用 serde_json 从 JSON 字符串转换为结构体的代码片段之外,您还可以从其字节表示形式转换为结构体:

let json_as_bytes = b" {   \"message\": \"Hello world!\",    }";

    let my_struct: MyStruct = serde_json::from_slice(json_as_bytes).unwrap();

如果您想将结构作为字节数组存储在某处,然后稍后将其转回结构,那么这特别有用!

同样,您也可以使用 .from_reader() 方法从 JSON IO 流读取 JSON 并将其转换为结构体。以下是取自 serde_json 文档的示例,说明如何将其与 TCP 流一起使用:

use serde::Deserialize;
use std::error::Error;
use std::net::{TcpListener, TcpStream};

#[derive(Deserialize, Debug)]
struct User {
    fingerprint: String,
    location: String,
}

fn read_user_from_stream(tcp_stream: TcpStream) -> Result<User, Box<dyn Error>> {
    let mut to_be_deserialized = serde_json::Deserializer::from_reader(tcp_stream);
    let user = User::deserialize(&mut to_be_deserialized)?;

    Ok(user)
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:4000").unwrap();

    for stream in listener.incoming() {
        println!("{:#?}", read_user_from_stream(stream.unwrap()));
    }
}

通过这种方式,您可以直接从流中反序列化,而不是在内存中添加缓冲。如果您收到大量基于 JSON 的数据,这可以为您提供很大帮助!

Comparing Rust JSON crates

比较 Rust JSON crates

尽管 serde-json 可能是最受欢迎的 crate,但它绝不是最快的。与此同时,还出现了一些其他 crate,以提高一般 JSON 解析性能。然而,为了换取性能,CPU SIMD 扩展要求存在一些注意事项。不安全代码的使用也有所增加,尽管一般来说,我们已尽最大努力确保代码可以安全使用。

所有这些 crate 大部分都具有相同的 API。除非另有说明,否则您可以安全地在这些库之间切换,并期望每个库中使用大致相同的 JSON 接口。

serde-json

serde-json 是最容易使用的 Rust JSON 库。它不需要额外的依赖项来使用,并且当您需要访问原始 JSON 值的惯用操作时,通常建议与 serde 一起使用。 serde-json 还支持 no_std ,允许您关闭默认的 std 功能并启用 alloc

就性能而言, serde-json 本身无论如何都不慢。但是,它比此列表中的其他一些 JSON 库慢。这主要是由于针对 非并行 CPU 使用进行了优化。特别是如果您能够访问现代 x86 CPU,您可能需要继续阅读以了解有关一些性能更好的选项的更多信息。然而,这个crate 也是 Rust 社区中使用最广泛和支持最多的,所以如果您遇到问题,那么很容易找到帮助!

simd-json

simd-jsonsimdjson C++ JSON 解析器的 Rust 语言绑定,内置了 serde 兼容性。顾名思义,该库使用 SIMD(单指令的缩写)多个数据。这是一种能够通过并行处理来处理多个数据点的技术,使其速度显着加快!但需要注意的是,它要求您的系统支持 x86,并且在运行时它将选择最佳的 SIMD 功能集以实现性能。如果没有可用的功能集,还有一个未优化的 Rust 实现,但在文档中提到不应依赖它。

文档中提到 simd-json 可以在本机目标编译上满负荷使用。您可以通过在运行程序时启用 rustc 中的以下编译器选项来做到这一点,如下所示:

rustc -C target-cpu=native

但是,如果您像大多数使用 Cargo 的人一样,您可能想使用 cargo run 。如示例中所示,您可以在 .cargo/config 处创建配置,然后添加以下内容:

[build]
rustflags = ["-C", "target-cpu=native"]

一般来说,虽然这个库相当快,但应该注意的是,由于它是 C++ 的 rust 语言绑定,因此该 crate 中存在相当多的不安全代码。这并不是说你不应该使用它,而是要谨慎使用它(正如crate所说)。尽管如此,有一个关于安全的部分详细介绍了如何坚持最佳实践(如单元测试)以确保crates尽可能安全地使用。

还应该提到的是,为了获得最佳性能,通常最好启用 jemallocmimalloc 功能,以便能够充分利用该库。

一般来说, simd-json 的 API 与 serde-json 相同,因此如果您想随时切换,那么通常这样做不会有任何问题。

sonic-rs

sonic-rs 是具有 SIMD 功能的 JSON 操作的 Rust 实现。该库还有 C++ 和 Go 中的对应库!虽然它过去需要 Rust nightly 工具链,但它支持稳定的 Rust。与 simd-json 类似,它也需要 x86 CPU 架构才能满负荷运行。

simd-json 一样,要使用 sonic-rs 您需要在运行程序时在 rustc 中启用以下编译器选项:

rustc -C target-cpu=native

您可以在 .cargo/config 创建配置,然后添加以下内容以在使用 cargo run 时启用它:

[build]
rustflags = ["-C", "target-cpu=native"]

这使您无需执行任何其他操作即可构建 SIMD!

simd-json 一样,使用了相当数量的 unsafe 代码。但是,如果您在库中搜索不安全代码,您可能会发现比以前的库中更多的 unsafe 代码。关于如何维护不安全保证的文档也很少,因此尽管这个库可能比 simd-json 更快,但您需要仔细检查是否存在未定义的行为!

sonic-rs 另外还有一些额外的方法用于惰性评估和额外的速度。例如,如果您想要 JSON 字符串文字,则可以在反序列化时使用 LazyValue 类型将其转换为仍包含正斜杠的 JSON 字符串值。如果您不怕不安全行为或者确定它不会出错,还有很多 unchecked 方法可以使用。

虽然 sonic-rs 是一个相当快的库,但它也是一个更新的 crate,因此 crate 中缺少一些方法,例如 from_reader (允许从 IO 流读取)。这已经作为 GitHub 问题提出,所以希望它能尽快实施。

基准

您可以在此处找到 simd-jsonserde-json 的基准。 simd-jsonserde-json 相比有相当显着的改进。

您可以在此处找到 sonic-rs 的基准,其中还将其与 simd-jsonserde-json 进行比较。正如您所看到的,最终结果的格式与 simd-jsonserde-json 基准测试的格式不同,因此每秒处理的数据量更难以理解。然而,在大多数情况下, sonic-rs 明显(有时是巨大!)比 simd-jsonserde-json 快。

尾声

谢谢阅读!我希望本文能够帮助您了解如何有效使用 Rust JSON 解析库。


原文地址:Parsing JSON in Rust

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1490864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

07 系统的线性时不变特性

各位看官&#xff0c;大家好&#xff01;本讲为《数字信号处理理论篇》07 系统的线性时不变特性。&#xff08;特别提示&#xff1a;课程内容为由浅入深的特性&#xff0c;而且前后对照&#xff0c;不要跳跃观看&#xff0c;请按照文章或视频顺序进行观看。 从本讲开始开始为大…

【Python】进阶学习:__len__()方法的使用介绍

【Python】进阶学习&#xff1a;__len__()方法的使用介绍 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到您的订…

shadertoy 游戏《来自星尘》摇杆复刻

正确的做法应该是上 noise 而不是叠加 sin 波&#xff0c;不过如果不想麻烦的话叠波还是一个不错的选择&#xff1a;整体效果如下&#xff0c;已经非常形似 直接上链接&#xff1a;Shader - Shadertoy BETA float radiusScale 0.9; float variation(vec2 v1, vec2 v2, float …

KCV(Key Check Value)的作用(验证密钥导入是否正确)与算法(DES/3DES或AES)示例

KCV的作用与算法 KCV&#xff08;Key Check Value&#xff09;的计算通常与加密算法有关&#xff0c;不同算法计算KCV的方式不同。以下是常见算法的KCV计算方法&#xff1a; DES/3DES算法&#xff1a; KCV是通过使用ECB模式的3DES加密8字节’00’来计算的。例如&#xff0c;…

【鸿蒙 HarmonyOS 4.0】弹性布局(Flex)

一、介绍 弹性布局&#xff08;Flex&#xff09;提供更加有效的方式对容器中的子元素进行排列、对齐和分配剩余空间。容器默认存在主轴与交叉轴&#xff0c;子元素默认沿主轴排列&#xff0c;子元素在主轴方向的尺寸称为主轴尺寸&#xff0c;在交叉轴方向的尺寸称为交叉轴尺寸…

Pipy 进化:从可编程代理到应用引擎

网络功能变得越来越复杂&#xff0c;编写和维护的难度提升&#xff1b;新的基于 Pipy 的应用中&#xff0c;Pipy 角色从数据平面变成控制面&#xff0c;需要执行更多复杂非网络的逻辑&#xff1b;从长远来看&#xff0c;Pipy 将更像是一个常见的类似 shell/bash 的系统脚本工具…

如何在MinIO系统中进行配置并结合内网穿透实现公网远程连接上传文件

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 前言 MinIO是一款高性能、分布式的对象存储系统&#xff0c;它可以100%的运行在标准硬件上&#xff0c;即X86等…

力扣hot100题解(python版33-35题)

33、排序链表 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&a…

你知道该如何使用 JS 创建 css 类样式吗?

前言 去年我为公司内部开发了一个浏览器插件&#xff0c;当时为了加快开发进度&#xff0c;我没有选用现成的插件框架&#xff0c;而是直接使用原生 JavaScript 搭配 Rollup 进行打包。由于这是一个浏览器插件&#xff0c;我不可避免地需要对页面元素进行操作&#xff0c;比如…

小太阳防倾倒开关原理

小太阳防倾倒开关是一种体积小巧、安装简便、灵敏度高的设备&#xff0c;其原理基于角度感应和光电技术。该开关具有精确的角度判断能力&#xff0c;无需机械接触&#xff0c;稳定性强&#xff0c;支持个性化角度设置&#xff0c;可根据需求进行水平、垂直或倒置安装。 在应用…

注意力机制(代码实现案例)

学习目标 了解什么是注意力计算规则以及常见的计算规则.了解什么是注意力机制及其作用.掌握注意力机制的实现步骤. 1 注意力机制介绍 1.1 注意力概念 我们观察事物时&#xff0c;之所以能够快速判断一种事物(当然允许判断是错误的), 是因为我们大脑能够很快把注意力放在事物…

STM32(16)使用串口向电脑发送数据

发送字节 发送数组 发送字符和字符串 字符&#xff1a; 字符串&#xff1a; 字符串在电脑中以字符数组的形式存储

最新AI系统ChatGPT网站H5系统源码,支持Midjourney绘画

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GPT…

《互联网的世界》第四讲-拥塞控制与编码

需要澄清的一个误区是&#xff0c;拥塞绝不是发送的数据量太大导致&#xff0c;而是数据在极短的时间段内到达了同一个地方以至于超过了网络处理容量导致&#xff0c;拥塞的成因一定要考虑时间因素。换句话说&#xff0c;拥塞由大突发导致。 只要 pacing&#xff0c;再多的数据…

MongoDB开启事务

MongoDB开启事务 配置单节点。到路径C:\Program Files\MongoDB\Server\4.0\bin 使用记事本以管理员权限打开文件mongod.cfg添加如下配置&#xff1a; replication:replSetName: rs02. 重启MongoDB服务 3. 重启后执行命令 rs.initiate()

Python采集学习笔记-request的get请求和post请求

使用http://httpbin.org测试,一个简单的 HTTP 请求和响应服务。(需联网)1.导入requests包 import requests 2.测试get请求 url http://httpbin.org/get par {key1: value1, key2: value2} # 不带参数请求 r1 requests.get(url) # 带参数请求 r2 requests.get(url, paramspa…

数据库管理-第158期 Oracle Vector DB AI-09(20240304)

数据库管理158期 2024-03-04 数据库管理-第158期 Oracle Vector DB & AI-09&#xff08;20240304&#xff09;1 创建示例表2 添加过滤条件的向量近似查询示例1示例2示例3示例4示例5示例6示例7 总结 数据库管理-第158期 Oracle Vector DB & AI-09&#xff08;20240304&a…

怎么采集GBK或GB2312等特殊字符编码的网站数据

如果要采集的网站是GBK或GB2312等特殊字符编码&#xff0c;采集结果可能是一堆看不懂的文字或乱码&#xff0c;无法使用。 通常网页文章采集工具有字符编码选项&#xff0c;默认是UTF-8&#xff08;现在大部分网站都是&#xff09;&#xff0c;改选为GBK或GB2312字符编码即可&…

无人机/飞控--ArduPilot、PX4学习历程记录(1)

本篇博客用来记录个人学习记录&#xff0c;存放各种文章链接、视频链接、学习历程、实验过程和结果等等.... 最近在整无人机项目&#xff0c;接触一下从来没有接触过的飞控...(听着就头晕)&#xff0c;本人纯小白。 目录 PX4、Pixhawk、APM、ArduPilot、Dronecode Dronekit…

【ArcPy】游标访问几何数据

访问质心坐标相关数据 结果展示 代码 import arcpy shppath r"C:\Users\admin\Desktop\excelfile\a2.shp" with arcpy.da.SearchCursor(shppath, ["SHAPE","SHAPEXY","SHAPETRUECENTROID","SHAPEX","SHAPEY",&q…