自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何在Rust中操作JSON,你學(xué)會(huì)了嗎?

開(kāi)發(fā) 前端
sonic-rs ?還具有一些額外的方法來(lái)進(jìn)行惰性評(píng)估和提高速度。例如,如果我們想要一個(gè) JSON? 字符串文字,我們可以在反序列化時(shí)使用 LazyValue? 類型將其轉(zhuǎn)換為一個(gè)仍然帶有斜杠的 JSON 字符串值。如果我們不怕不安全行為,或者確信它不會(huì)出錯(cuò),還有很多未經(jīng)檢查的方法可供我們使用。

前言

我們之前在Rust 賦能前端-開(kāi)發(fā)一款屬于你的前端腳手架中有過(guò)在Rust項(xiàng)目中如何操作JSON。

圖片圖片

由于文章篇幅的原因,我們就沒(méi)詳細(xì)介紹這塊的內(nèi)容,而今天我們就抽空聊聊這個(gè)話題。-- 「如何在Rust中操作JSON,以及對(duì)最流行的庫(kù)進(jìn)行比較」

好了,天不早了,干點(diǎn)正事哇。

我們能所學(xué)到的知識(shí)點(diǎn)

  1. 操作JSON數(shù)據(jù)
  2. 比較 Rust 的 JSON crates

1. 操作JSON數(shù)據(jù)

創(chuàng)建JSON數(shù)據(jù)

要在Rust中處理JSON,我們可以借助相關(guān)的JSON庫(kù)。其實(shí)市面上有很多相關(guān)的庫(kù),但是我們還是選擇一種我們比較熟悉并且流行度高的庫(kù)。--serde-json[1]

我們可以通過(guò)運(yùn)行以下命令來(lái)安裝它:

cargo add serde-json

完成后,我們可以像這樣手動(dòng)創(chuàng)建JSON:

use serde_json::{Result, Value};

fn untyped_example() -> Result<()> {
    // 一些JSON輸入數(shù)據(jù),作為一個(gè)&str。也許這些數(shù)據(jù)來(lái)自用戶。
    let data = r#"
        {
            "name": "Front789",
            "age": 18,
            "ability": [
                "Front-end development",
                "Rust",
                "AI"
            ]
        }"#;

    // 將數(shù)據(jù)字符串解析為serde_json::Value。
    let v: Value = serde_json::from_str(data)?;

    // 通過(guò)使用方括號(hào)索引來(lái)訪問(wèn)數(shù)據(jù)的部分。
    println!("我是{}。一個(gè)專注于{}/{}及{}應(yīng)用知識(shí)分享**的Coder", 
    v["name"], v["ability"][0],v["ability"][1],v["ability"][2]);

    Ok(())
}

然而,我們可以做得比這更好。例如,我們可以將JSON序列化為結(jié)構(gòu)體,這在許多應(yīng)用中都有用途。我們可以在JSON模板、Web服務(wù)、CLI參數(shù)(這點(diǎn)我們的f_cli[2]就使用了它)等方面使用它。

當(dāng)然,我們也可以使用std::fs::write來(lái)將這些JSON數(shù)據(jù)寫入到磁盤文件中。

使用Serde解析JSON

Serde是一個(gè)crate,它幫助我們將數(shù)據(jù)序列化和反序列化為各種格式,其中一個(gè)流行的用途是用于JSON。Serde提供了兩個(gè)主要的trait來(lái)幫助我們完成這一點(diǎn):Serialize和Deserialize。我們可以添加了一個(gè)派生宏實(shí)現(xiàn)來(lái)幫助我們完成這一點(diǎn)。

use serde::{Deserialize, Serialize};

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

fn convert_json_to_struct() {
    // 從json!宏創(chuàng)建一個(gè)原始的JSON字符串,并將其轉(zhuǎn)換為MyStruct結(jié)構(gòu)體
    let raw_json_string = json!({"message": "Hello Front789!"});
    let my_struct: MyStruct = serde_json::from_str(raw_json_string).unwrap();
}

我們還可以創(chuàng)建「嵌套的JSON」,方法是將實(shí)現(xiàn)Serialize和Deserialize的結(jié)構(gòu)體作為另一個(gè)也實(shí)現(xiàn)Serialize和Deserialize的結(jié)構(gòu)體的字段:

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創(chuàng)建一個(gè)Web服務(wù)(還記得我們之前介紹過(guò)的Rust Web 開(kāi)發(fā)之Axum使用手冊(cè)嗎),并且返回一個(gè)嵌套JSON。例如,當(dāng)我們的Web服務(wù)器收到一個(gè)POST請(qǐng)求,其Body中是一個(gè)Json數(shù)據(jù)時(shí),我們通常會(huì)將相關(guān)的Json類型作為處理程序函數(shù)的參數(shù)傳遞。

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(
  // 這個(gè)提取器消耗一個(gè)JSON主體,并將其轉(zhuǎn)換為給定的結(jié)構(gòu)類型
    Json(json): Json<Post>
) -> Json<Post> {
    println!("{:?}", json);
    Json(json)
}

我們還可以從其字節(jié)表示形式轉(zhuǎn)換為結(jié)構(gòu)體:

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

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

上面的處理方式,在我們想將一個(gè)結(jié)構(gòu)體存儲(chǔ)在某個(gè)地方作為字節(jié)數(shù)組,然后再將其轉(zhuǎn)換回結(jié)構(gòu)體時(shí),有奇特的效果!

類似地,我們還可以從JSON的「IO流」中讀取JSON并將其轉(zhuǎn)換為結(jié)構(gòu)體,使用.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()));
    }
}

這樣,當(dāng)我們?cè)谟龅叫枰幚鞪SON的數(shù)據(jù)時(shí),我們就可以直接從流中反序列化,而不是在內(nèi)存中添加緩沖區(qū)。

2. 比較 Rust 的 JSON crates

其實(shí),在大部分情況下,serde-json已經(jīng)能夠滿足我們的需求了。但是,在一些特殊情況下,例如數(shù)據(jù)量過(guò)大,此時(shí)serde-json就有點(diǎn)吃力了。所以,市面上又有了一些提高 JSON 解析性能的crate。(simd-json/sonic-rs)

圖片圖片

從上圖可知serde-json有碾壓式優(yōu)勢(shì),也就是不到萬(wàn)不得已,我們還是使用serde-json。不過(guò),本著知己知彼,方能百戰(zhàn)不殆。我們也需要知曉額外的解決方案。

這些 crates 大部分具有相同的 API。除非另有說(shuō)明,否則我們可以安全地在這些庫(kù)之間切換,并期望在每個(gè)庫(kù)中使用 JSON 時(shí)具有大致相同的接口。

serde-json

serde-json 是 Rust 中下載和使用最多的 JSON 庫(kù)之一。

就性能而言,serde-json 本身并不慢。然而,然后對(duì)比其他兩個(gè)crate就有點(diǎn)稍遜了。這主要是因?yàn)樗徊捎梅遣⑿谢?nbsp;CPU 使用架構(gòu)。這樣的話,serde-json就無(wú)法在x86 CPU的系統(tǒng)架構(gòu)上,發(fā)揮更強(qiáng)的作用。

x86 是一種廣泛使用的中央處理單元 (CPU) 計(jì)算機(jī)架構(gòu)。它已成為個(gè)人計(jì)算機(jī)和服務(wù)器的主導(dǎo)架構(gòu)。x86這個(gè)名稱源自 8086,這是英特爾? 發(fā)布的早期處理器。x86 CPU 使用「復(fù)雜指令集計(jì)算機(jī)」 (CISC) 設(shè)計(jì),允許它們?cè)凇竼蝹€(gè)周期內(nèi)執(zhí)行多條指令」。x想了解更多關(guān)于x86 CPU的內(nèi)容,可以參考x86介紹[3]

simd-json

simd-json[4] 是 simdjson C++ JSON 解析器的 Rust 版本,內(nèi)置了 serde 兼容性。正如其名稱所示,此庫(kù)使用 SIMD(單指令多數(shù)據(jù))。這是一種用于能夠使用并行處理處理多個(gè)數(shù)據(jù)點(diǎn)的技術(shù),使其速度顯著更快!然而,作為一個(gè)注意事項(xiàng),它要求我們的系統(tǒng)具有 x86 能力,并且在運(yùn)行時(shí)會(huì)選擇最佳的 SIMD 特性集以獲得性能。

文檔中提到 simd-json 可以在本機(jī)目標(biāo)編譯時(shí)充分發(fā)揮作用。我們可以通過(guò)在運(yùn)行程序時(shí)啟用 rustc 中的以下編譯器選項(xiàng)來(lái)實(shí)現(xiàn)此目標(biāo),例如:

rustc -C target-cpu=native

然而,如果我們像大多數(shù)使用 Cargo 的人一樣,我們可能想使用 cargo run。與示例中一樣,我們可以在 .cargo/config 中創(chuàng)建一個(gè)配置,然后添加以下內(nèi)容:

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

在.cargo/config配置相關(guān)的內(nèi)容,我們?cè)赗ust交叉編譯Windows環(huán)境時(shí)候,也涉及到。

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

一般來(lái)說(shuō),盡管這個(gè)庫(kù)非???,但應(yīng)該注意到這個(gè) crate 中有相當(dāng)多的不安全代碼,因?yàn)樗?nbsp;C++ crate 的一個(gè)移植。這并不意味著我們不應(yīng)該使用它,而是要謹(jǐn)慎使用。

還應(yīng)該提到的是,為了獲得最佳性能,通常最好啟用 jemalloc 或 mimalloc 特性,以充分利用庫(kù)。

通常情況下,simd-json 的 API 與 serde-json 相同,因此如果我們想在任何時(shí)候切換,通常不應(yīng)該遇到任何問(wèn)題。

sonic-rs

sonic-rs[5] 是具有 SIMD 功能的 JSON 操作的 Rust 實(shí)現(xiàn)。這個(gè)庫(kù)還有一個(gè) C++ 和 Go 的對(duì)應(yīng)庫(kù)!盡管它曾經(jīng)需要 Rust nightly 工具鏈,但現(xiàn)在支持穩(wěn)定的 Rust。與 simd-json 類似,它也需要 x86 CPU 架構(gòu)才能充分發(fā)揮作用。

與 simd-json 一樣,要使用 sonic-rs,我們需要在運(yùn)行程序時(shí)啟用 rustc 中的以下編譯器選項(xiàng):

rustc -C target-cpu=native

我們可以在 .cargo/config 中創(chuàng)建一個(gè)配置,然后添加以下內(nèi)容以在使用 cargo run 時(shí)啟用它:

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

這樣我們就可以構(gòu)建支持 SIMD 的程序而無(wú)需做其他操作!

與 simd-json 類似,這個(gè)庫(kù)中使用了相當(dāng)多的不安全代碼。然而,如果我們?cè)趲?kù)中搜索不安全代碼,我們會(huì)發(fā)現(xiàn)比之前的庫(kù)中的不安全代碼可能更多。

sonic-rs 還具有一些額外的方法來(lái)進(jìn)行惰性評(píng)估和提高速度。例如,如果我們想要一個(gè) JSON 字符串文字,我們可以在反序列化時(shí)使用 LazyValue 類型將其轉(zhuǎn)換為一個(gè)仍然帶有斜杠的 JSON 字符串值。如果我們不怕不安全行為,或者確信它不會(huì)出錯(cuò),還有很多未經(jīng)檢查的方法可供我們使用。

盡管 sonic-rs 是一個(gè)非??斓膸?kù),但它也是一個(gè)較新的 crate,因此某些方法,如 from_reader(允許從 IO 流讀?。┰?nbsp;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

責(zé)任編輯:武曉燕 來(lái)源: 前端柒八九
相關(guān)推薦

2023-10-10 11:04:11

Rust難點(diǎn)內(nèi)存

2023-12-27 07:31:45

json產(chǎn)品場(chǎng)景

2024-04-09 13:16:21

Rust命名規(guī)范

2024-01-05 07:46:15

JS克隆對(duì)象JSON

2023-10-31 14:04:17

Rust類型編譯器

2024-04-29 06:55:34

RustMIDI應(yīng)用程序

2022-11-30 09:54:57

網(wǎng)絡(luò)令牌身份驗(yàn)證

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機(jī)器學(xué)習(xí)模型

2024-12-05 10:53:02

JSON數(shù)據(jù)服務(wù)器

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2023-07-26 13:11:21

ChatGPT平臺(tái)工具

2024-01-19 08:25:38

死鎖Java通信

2023-01-10 08:43:15

定義DDD架構(gòu)

2023-10-13 09:04:09

2021-11-26 11:30:07

身高重建隊(duì)列

2024-05-29 09:20:41

2023-04-26 00:41:36

A/B測(cè)試郵件數(shù)量

2024-08-09 08:17:07

SSH服務(wù)器架構(gòu)

2024-08-21 08:27:30

擴(kuò)展數(shù)據(jù)庫(kù)服務(wù)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)