如何在Rust中操作JSON

越努力,越幸运

大家好,我是「柒八九」。一个「专注于前端开发技术/RustAI应用知识分享」Coder

前言

我们之前在Rust 赋能前端-开发一款属于你的前端脚手架中有过在Rust项目中如何操作JSON

alt

由于文章篇幅的原因,我们就没详细介绍这块的内容,而今天我们就抽空聊聊这个话题。 -- 「如何在Rust中操作JSON,以及对最流行的库进行比较」

好了,天不早了,干点正事哇。

alt

我们能所学到的知识点

  1. 操作JSON数据
  2. 比较 Rust 的 JSON crates

1. 操作JSON数据

创建JSON数据

要在Rust中处理JSON,我们可以借助相关的JSON库。其实市面上有很多相关的库,但是我们还是选择一种我们比较熟悉并且流行度高的库。--serde-json[1]

我们可以通过运行以下命令来安装它:

cargo add serde-json

完成后,我们可以像这样手动创建JSON

use serde_json::{Result, Value};

fn untyped_example() -> Result<()> {
    // 一些JSON输入数据,作为一个&str。也许这些数据来自用户。
    let data = r#"
        {
            "name": "Front789",
            "age": 18,
            "ability": [
                "Front-end development",
                "Rust",
                "AI"
            ]
        }"#
;

    // 将数据字符串解析为serde_json::Value。
    let v: Value = serde_json::from_str(data)?;

    // 通过使用方括号索引来访问数据的部分。
    println!("我是{}。一个专注于{}/{}及{}应用知识分享**的Coder"
    v["name"], v["ability"][0],v["ability"][1],v["ability"][2]);

    Ok(())
}

然而,我们可以做得比这更好。例如,我们可以将JSON序列化为结构体,这在许多应用中都有用途。我们可以在JSON模板Web服务CLI参数(这点我们的f_cli[2]就使用了它)等方面使用它。

当然,我们也可以使用std::fs::write来将这些JSON数据写入到磁盘文件中。

使用Serde解析JSON

Serde是一个crate,它帮助我们将数据序列化和反序列化为各种格式,其中一个流行的用途是用于JSONSerde提供了两个主要的trait来帮助我们完成这一点:SerializeDeserialize。我们可以添加了一个派生宏实现来帮助我们完成这一点。

use serde::{Deserialize, Serialize};

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

fn convert_json_to_struct() {
    // 从json!宏创建一个原始的JSON字符串,并将其转换为MyStruct结构体
    let raw_json_string = json!({"message""Hello Front789!"});
    let my_struct: MyStruct = serde_json::from_str(raw_json_string).unwrap();
}

我们还可以创建「嵌套的JSON」,方法是将实现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>,
}

上面的代码可以用于我们用Rust创建一个Web服务(还记得我们之前介绍过的Rust Web 开发之Axum使用手册吗),并且返回一个嵌套JSON。例如,当我们的Web服务器收到一个POST请求,其Body中是一个Json数据时,我们通常会将相关的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(
  // 这个提取器消耗一个JSON主体,并将其转换为给定的结构类型
    Json(json): Json<Post>
) -> Json<Post> {
    println!("{:?}", json);
    Json(json)
}

我们还可以从其字节表示形式转换为结构体:

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

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

上面的处理方式,在我们想将一个结构体存储在某个地方作为字节数组,然后再将其转换回结构体时,有奇特的效果!

类似地,我们还可以从JSON「IO流」中读取JSON并将其转换为结构体,使用.from_reader()方法。以下代码中展示了如何在TCP流中使用它:

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

#[derive(Deserialize, Debug)]
struct User {
    name: String,
    age: 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:7890").unwrap();

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

这样,当我们在遇到需要处理JSON的数据时,我们就可以直接从流中反序列化,而不是在内存中添加缓冲区。


2. 比较 Rust 的 JSON crates

其实,在大部分情况下,serde-json已经能够满足我们的需求了。但是,在一些特殊情况下,例如数据量过大,此时serde-json就有点吃力了。所以,市面上又有了一些提高 JSON 解析性能的crate。(simd-json/sonic-rs)

alt

从上图可知serde-json有碾压式优势,也就是不到万不得已,我们还是使用serde-json。不过,本着知己知彼,方能百战不殆。我们也需要知晓额外的解决方案。

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

serde-json

serde-jsonRust 中下载和使用最多的 JSON 库之一。

就性能而言,serde-json 本身并不慢。然而,然后对比其他两个crate就有点稍逊了。这主要是因为它被采用非并行化的 CPU 使用架构。这样的话,serde-json就无法在x86 CPU的系统架构上,发挥更强的作用。

x86 是一种广泛使用的中央处理单元 (CPU) 计算机架构。它已成为个人计算机和服务器的主导架构。 x86这个名称源自 8086,这是英特尔® 发布的早期处理器。 x86 CPU 使用「复杂指令集计算机」 (CISC) 设计,允许它们在「单个周期内执行多条指令」。x想了解更多关于x86 CPU的内容,可以参考x86介绍[3]

simd-json

simd-json[4]simdjson C++ JSON 解析器的 Rust 版本,内置了 serde 兼容性。正如其名称所示,此库使用 SIMD(单指令多数据)。这是一种用于能够使用并行处理处理多个数据点的技术,使其速度显著更快!然而,作为一个注意事项,它要求我们的系统具有 x86 能力,并且在运行时会选择最佳的 SIMD 特性集以获得性能。

文档中提到 simd-json 可以在本机目标编译时充分发挥作用。我们可以通过在运行程序时启用 rustc 中的以下编译器选项来实现此目标,例如:

rustc -C target-cpu=native

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

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

.cargo/config配置相关的内容,我们在Rust交叉编译Windows环境时候,也涉及到。

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"

一般来说,尽管这个库非常快,但应该注意到这个 crate 中有相当多的不安全代码,因为它是 C++ crate 的一个移植。这并不意味着我们不应该使用它,而是要谨慎使用。

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

通常情况下,simd-json 的 API 与 serde-json 相同,因此如果我们想在任何时候切换,通常不应该遇到任何问题。

sonic-rs

sonic-rs[5] 是具有 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 类似,这个库中使用了相当多的不安全代码。然而,如果我们在库中搜索不安全代码,我们会发现比之前的库中的不安全代码可能更多。

sonic-rs 还具有一些额外的方法来进行惰性评估和提高速度。例如,如果我们想要一个 JSON 字符串文字,我们可以在反序列化时使用 LazyValue 类型将其转换为一个仍然带有斜杠的 JSON 字符串值。如果我们不怕不安全行为,或者确信它不会出错,还有很多未经检查的方法可供我们使用。

尽管 sonic-rs 是一个非常快的库,但它也是一个较新的 crate,因此某些方法,如 from_reader(允许从 IO 流读取)在 crate 中缺失。


后记

「分享是一种态度」

「全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。」

alt

Reference

[1]

serde-json: https://crates.io/crates/serde_json

[2]

f_cli: https://www.npmjs.com/package/f_cli_f

[3]

x86介绍: https://www.lenovo.com/us/en/glossary/x86/

[4]

simd-json: https://crates.io/crates/simd-json

[5]

sonic-rs: https://crates.io/crates/sonic-rs

本文由 mdnice 多平台发布

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

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

相关文章

基于SSM的教材管理系统

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的教材管理系统2拥有两种角色 管理员&#xff1a;教师管理、分类管理、教材管理、入库和出库管理、教材申请管理等 教师&#xff1a;查看教材、申请教材 1.1 背景描述 SSM教材管…

服务器数据恢复—EqualLogic PS6100系列存储数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌EqualLogic PS6100系列存储阵列是一款容错功能较强的存储设备&#xff0c;具有较高的安全性能。一些硬件故障或者误操作也会破坏该系列存储内的数据&#xff0c;下面分享一个北亚企安数据恢复工程师接到的一个关于EQ PS6100存储的数据恢复…

java版数字藏品深色UI仿鲸探数藏盲盒合成短视频卡牌模式支持高并发

Java版数字藏品深色UI仿鲸探数藏盲盒合成短视频卡牌模式支持高并发&#xff0c;是一种结合了Java技术、深色用户界面&#xff08;UI&#xff09;设计、数字藏品概念、盲盒合成玩法以及短视频卡牌模式的综合性应用。该模式旨在为用户提供一种新颖、有趣的数字藏品体验&#xff0…

LC 450.删除二叉搜索树中的节点

450.删除二叉搜索树中的节点 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜索树的性质不变。返回二叉搜索树&#xff08;有可能被更新&#xff09;的根节点的引用。 一般来说&#xff0c;删除节点可分…

解锁CodeGeeX智能问答中3项独有的隐藏技能

CodeGeeX是一款强大的AI编程助手&#xff0c;它能帮你快速解决编程中的各种问题。无论是代码调试、功能实现&#xff0c;还是学习新语言&#xff0c;CodeGeeX都能助你一臂之力。 在IDE中搜索“CodeGeeX”就可以免费下载使用 CodeGeeX在侧边栏提供的Ask CodeGeeX智能问答功能&a…

代码随想录-算法训练营day04【链表02:两两交换链表中的节点、删除链表的倒数第N个节点、链表相交、环形链表II】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第二章 链表part02● day 1 任务以及具体安排&#xff1a;https://docs.qq.com/doc/DUG9UR2ZUc3BjRUdY ● day 2 任务以及具体安排&#xff1a;https://docs.qq.com/doc/DUGRwWXNOVEpyaVpG ● day 3 任务以及具体安排…

C++第十六弹---string使用(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、标准库中的string类 1.1、string类的常用接口说明 1.1.1、string类对象的常见构造 1.1.2、string类对象的容量操作 1.1.3、string类对象的…

网上打印a4纸大概多少钱一张

在快节奏的现代生活中&#xff0c;网上打印服务因其便捷性而受到越来越多用户的青睐。对于许多需要打印大量文件的用户来说&#xff0c;了解网上打印A4纸的价格至关重要。那么&#xff0c;网上打印A4纸300页大概需要多少钱呢&#xff1f; 网上打印价格取决于多个因素&#xff…

Severt和tomcat的使用(补充)

打包程序 在pom.xml中添加上述代码之后打包时会生成war包并且包的名称是test 默认情况打的是jar包.jar里量但是tomcat要求的是war包. war包Tomcat专属的压缩包. war里面不光有.class还有一些tomcat要求的配置文件(web.xml等)还有前端的一些代码(html, css, js) 点击其右边的m…

前端学习<四>JavaScript基础——14-基本包装类型

基本数据类型不能绑定属性和方法 属性和方法只能添加给对象&#xff0c;不能添加给基本数据类型。我们拿字符串来举例。 1、基本数据类型&#xff1a; 基本数据类型string是无法绑定属性和方法的。 var str qianguyihao;​str.aaa 12;console.log(typeof str); //打印结果…

十大经典排序算法及其C语言实现--带动图展示

排序算法大概算起来有以下十种 一、冒泡排序&#xff08;Bubble Sort&#xff09; 冒泡排序&#xff08;Bubble Sort&#xff09;也是一种简单直观的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。走访数…

python统计分析——一般线性回归模型

参考资料&#xff1a;python统计分析【托马斯】 当我想用一个或多个其他的变量预测一个变量的时候&#xff0c;我们可以用线性回归的方法。 例如&#xff0c;当我们寻找给定数据集的最佳拟合线的时候&#xff0c;我们是在寻找让下式的残差平方和最小的参数(k,d)&#xff1a; 其…

基于51单片机的秒表设计—0.01精度99.99s

基于51单片机的秒表设计 &#xff08;仿真&#xff0b;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.数码管显示秒表&#xff0c;精度为0.01&#xff1b; 2.记时最大为99.99s,过后清零记数。 3.一个按键实现开始…

突破传统,创新营销:淘宝天猫详情接口API的无限可能

随着互联网的迅猛发展&#xff0c;电子商务平台成为了现代商业营销的重要组成部分。淘宝和天猫作为中国最大的电子商务平台之一&#xff0c;拥有庞大的商品数据库和海量的买家资源。为了更好地实现个性化、精准化的营销策略&#xff0c;淘宝天猫推出了详情接口API&#xff0c;联…

Kibana管理ES生命周期

希望通过Kibana界面管理ES索引的生命周期 版本&#xff1a;7.15.2 创建索引模板 创建索引模板方便匹配索引&#xff0c;对匹配到的一批索引采用同一套生命周期管理策略&#xff0c;例如开发环境的所有索引以dev-开头&#xff0c;可以创建样式为dev-*的索引模板以匹配开发环境…

uni-starter和uni-admin初始化

1. 初始化uni-starter项目之后需要在uniCloud–>cloudfunctions–>common–>uni-config-center下面新增uni-id文件夹&#xff0c;下面新增config.json文件。 1.1配置好tokenSecret和微信的appId&#xff0c;appSecret等,如下&#xff1a; {"passwordSecret"…

pygame旋转角度发射射线

self.x self.x math.cos(math.radians(self.xuanzhuanjiao)) * 70 self.y self.y - math.sin(math.radians(self.xuanzhuanjiao)) * 70 旋转角度&#xff0c;70是间隔 间隔太小会卡 import pygame from pygame.locals import * import sys import mathpygame.init()width, …

03-JAVA设计模式-装饰模式

装饰模式 什么装饰模式 装饰器模式&#xff08;Decorator Pattern&#xff09;也叫包装器模式&#xff0c;是一种结构型设计模式&#xff0c;允许用户在不改变对象的情况下&#xff0c;动态地给对象增加一些额外的职责&#xff08;功能&#xff09;。装饰器模式相比生成子类更…

echarts 多环形图

环形图效果&#xff1a; option {"angleAxis": {"max": 1,"show": false,"splitLine": {"show": false},"axisLabel": {"show": false},"axisTick": {"show": false}},"ra…

美国N4433A安捷伦电子校准件

181/2461/8938产品概述&#xff1a; 安捷伦N4433A微波电子校准&#xff08;ECal&#xff09;模块使矢量网络分析仪的校准变得快速、简单和准确。ECal是一种用于矢量网络分析仪的精密单连接校准技术。与机械校准套件相比&#xff0c;使用ECal进行完整的三端口或四端口校准所需的…