您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Rust

如何在Rust中操作JSON,你学会了吗?

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

前言

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

图片图片

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

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

我们能所学到的知识点

  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,它帮助我们将数据序列化和反序列化为各种格式,其中一个流行的用途是用于JSON。Serde提供了两个主要的trait来帮助我们完成这一点:Serialize和Deserialize。我们可以添加了一个派生宏实现来帮助我们完成这一点。

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」,方法是将实现Serialize和Deserialize的结构体作为另一个也实现Serialize和Deserialize的结构体的字段:

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)

图片图片

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

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

serde-json

serde-json 是 Rust 中下载和使用最多的 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 的一个移植。这并不意味着我们不应该使用它,而是要谨慎使用。

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

通常情况下,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 中缺失。

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



Tags:Rust   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
在Rust中使用Serde的详细指南
在处理HTTP请求时,我们总是需要在一种数据结构(可以是enum、struct等)和一种可以存储或传输并稍后重建的格式(例如JSON)之间来回转换。Serde是一个库(crate),用于高效、通用地...【详细内容】
2024-03-26  Search: Rust  点击:(13)  评论:(0)  加入收藏
Rust 写脚手架,Clap你应该知道的二三事
有感而发最近,在和前端小伙伴聊天发现,在2024年,她们都有打算入局Rust学习的行列。毕竟前端现在太卷了,框架算是走到「穷途末路」了,无非就是在原有基础上修修补补。所有他们想在...【详细内容】
2024-03-11  Search: Rust  点击:(20)  评论:(0)  加入收藏
前端开始“锈化”?Vue团队开源JS打包工具:基于Rust、速度极快、尤雨溪主导
Vue 团队已正式开源Rolldown &mdash;&mdash; 基于 Rust 的 JavaScrip 打包工具。Rolldown 是使用 Rust 开发的 Rollup 替代品,它提供与 Rollup 兼容的应用程序接口和插件接口...【详细内容】
2024-03-09  Search: Rust  点击:(11)  评论:(0)  加入收藏
Rust中的数据可视化指南
可视化是数据分析和解释的一个关键方面。虽然Rust主要以其性能和安全特性而闻名,但它也为数据可视化提供了强大的工具。在这个全面的指南中,我们将深入研究Rust中的数据可视化...【详细内容】
2024-03-07  Search: Rust  点击:(29)  评论:(0)  加入收藏
如何在Rust中操作JSON,你学会了吗?
sonic-rs ​还具有一些额外的方法来进行惰性评估和提高速度。例如,如果我们想要一个 JSON​ 字符串文字,我们可以在反序列化时使用 LazyValue​ 类型将其转换为一个仍然带有斜...【详细内容】
2024-02-27  Search: Rust  点击:(47)  评论:(0)  加入收藏
记一次Rust内存泄漏排查之旅
在某次持续压测过程中,我们发现 GreptimeDB 的 Frontend 节点内存即使在请求量平稳的阶段也在持续上涨,直至被 OOM kill。我们判断 Frontend 应该是有内存泄漏了,于是开启了排...【详细内容】
2024-02-27  Search: Rust  点击:(12)  评论:(0)  加入收藏
Rust 最受欢迎的这些库
今天分享主题是,关于一些值得注意的 Rust 库,这些库可以根据它们的功能和在编码中的受欢迎程度进行选择。什么是 Rust 库?在 Rust 中,常被称为 “crate” 的库,是一个打包的单元...【详细内容】
2024-02-19  Search: Rust  点击:(50)  评论:(0)  加入收藏
异步Rust:构建实时消息代理服务器
在本文中,我们将深入研究使用Rust构建实时消息代理服务器,展示其强大的并发特性。我们将使用Warp作为web服务器,并使用Tokio来管理异步任务。此外,我们将创建一个WebSocket客户...【详细内容】
2024-02-01  Search: Rust  点击:(57)  评论:(0)  加入收藏
在 Rust 编程中使用泛型
本文的内容将涉及泛型定义函数、结构体、枚举和方法, 还将讨论泛型如何影响代码性能。1.摘要Rust中的泛型可以让我们为像函数签名或结构体这样的项创建定义, 这样它们就可以...【详细内容】
2024-01-09  Search: Rust  点击:(89)  评论:(0)  加入收藏
什么是Rust语言 ,特点是什么,跟其它语言对比有什么优势
什么是RustRust是一种系统编程语言,旨在提供高性能和安全性。它是由Mozilla和其开发社区创建的开源语言,设计目标是在C++的应用场景中提供一种现代、可靠和高效的选择。Rust的...【详细内容】
2024-01-09  Search: Rust  点击:(202)  评论:(0)  加入收藏
▌简易百科推荐
在Rust中使用Serde的详细指南
在处理HTTP请求时,我们总是需要在一种数据结构(可以是enum、struct等)和一种可以存储或传输并稍后重建的格式(例如JSON)之间来回转换。Serde是一个库(crate),用于高效、通用地...【详细内容】
2024-03-26  coding到灯火阑珊  微信公众号  Tags:Rust   点击:(13)  评论:(0)  加入收藏
Rust 写脚手架,Clap你应该知道的二三事
有感而发最近,在和前端小伙伴聊天发现,在2024年,她们都有打算入局Rust学习的行列。毕竟前端现在太卷了,框架算是走到「穷途末路」了,无非就是在原有基础上修修补补。所有他们想在...【详细内容】
2024-03-11  前端柒八九  微信公众号  Tags:Rust   点击:(20)  评论:(0)  加入收藏
Rust中的数据可视化指南
可视化是数据分析和解释的一个关键方面。虽然Rust主要以其性能和安全特性而闻名,但它也为数据可视化提供了强大的工具。在这个全面的指南中,我们将深入研究Rust中的数据可视化...【详细内容】
2024-03-07  coding到灯火阑珊  微信公众号  Tags:Rust   点击:(29)  评论:(0)  加入收藏
如何在Rust中操作JSON,你学会了吗?
sonic-rs ​还具有一些额外的方法来进行惰性评估和提高速度。例如,如果我们想要一个 JSON​ 字符串文字,我们可以在反序列化时使用 LazyValue​ 类型将其转换为一个仍然带有斜...【详细内容】
2024-02-27  前端柒八九  微信公众号  Tags:Rust   点击:(47)  评论:(0)  加入收藏
记一次Rust内存泄漏排查之旅
在某次持续压测过程中,我们发现 GreptimeDB 的 Frontend 节点内存即使在请求量平稳的阶段也在持续上涨,直至被 OOM kill。我们判断 Frontend 应该是有内存泄漏了,于是开启了排...【详细内容】
2024-02-27  OSC开源社区    Tags:Rust   点击:(12)  评论:(0)  加入收藏
Rust 最受欢迎的这些库
今天分享主题是,关于一些值得注意的 Rust 库,这些库可以根据它们的功能和在编码中的受欢迎程度进行选择。什么是 Rust 库?在 Rust 中,常被称为 “crate” 的库,是一个打包的单元...【详细内容】
2024-02-19  码农渔夫  微信公众号  Tags:Rust   点击:(50)  评论:(0)  加入收藏
异步Rust:构建实时消息代理服务器
在本文中,我们将深入研究使用Rust构建实时消息代理服务器,展示其强大的并发特性。我们将使用Warp作为web服务器,并使用Tokio来管理异步任务。此外,我们将创建一个WebSocket客户...【详细内容】
2024-02-01      Tags:Rust   点击:(57)  评论:(0)  加入收藏
在 Rust 编程中使用泛型
本文的内容将涉及泛型定义函数、结构体、枚举和方法, 还将讨论泛型如何影响代码性能。1.摘要Rust中的泛型可以让我们为像函数签名或结构体这样的项创建定义, 这样它们就可以...【详细内容】
2024-01-09  二进制空间安全  微信公众号  Tags:Rust   点击:(89)  评论:(0)  加入收藏
什么是Rust语言 ,特点是什么,跟其它语言对比有什么优势
什么是RustRust是一种系统编程语言,旨在提供高性能和安全性。它是由Mozilla和其开发社区创建的开源语言,设计目标是在C++的应用场景中提供一种现代、可靠和高效的选择。Rust的...【详细内容】
2024-01-09    简易百科  Tags:Rust语言   点击:(202)  评论:(0)  加入收藏
在 Rust 编程中使用多线程
编程语言有一些不同的方法来实现线程,而且很多操作系统提供了创建新线程的 API。Rust 标准库使用 1:1 线程实现,这代表程序的每一个语言级线程使用一个系统线程。1. Rust线程...【详细内容】
2024-01-07  二进制空间安全  微信公众号  Tags:Rust 编程   点击:(77)  评论:(0)  加入收藏
站内最新
站内热门
站内头条