مقدمة: لماذا JSON مهم لمطور Rust
JSON (JavaScript Object Notation) يظل أحد أكثر تنسيقات تبادل البيانات شيوعًا في تطوير الويب والخدمات المصغرة وAPI. بالنسبة للغة Rust، التي تكتسب شعبية بسرعة بفضل أدائها وأمانها، فإن العمل مع JSON يعد مهمة بالغة الأهمية. سواء كنت مطورًا للواجهة الخلفية باستخدام Actix أو Rocket، أو تكتب أداة CLI، أو تعمل مع WebSockets، فإن القدرة على تحليل (Parsing) وتسلسل (Serializing) JSON في Rust ستفيدك بالتأكيد.
في هذه المقالة، سنشرح كيفية العمل بكفاءة مع JSON في Rust باستخدام النظام البيئي القياسي للحزم (crates) serde و serde_json. ستتعلم كيفية تحويل هياكل البيانات إلى JSON والعكس، ومعالجة الأخطاء، والعمل مع البيانات الديناميكية.
الأساسيات: تثبيت وإضافة التبعيات
للعمل مع JSON في Rust، يُستخدم إطار العمل القوي للتسلسل Serde وتنفيذه الخاص بـ JSON وهو الحزمة serde_json. للبدء، أضفهم إلى ملف Cargo.toml الخاص بك:
[dependencies]serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"العلامة features = ["derive"] تسمح باستخدام الماكرو #[derive(Serialize, Deserialize)]، مما يبسط الكود بشكل كبير.
التحليل الأساسي لسلسلة JSON
أبسط طريقة للبدء هي تحليل سلسلة JSON إلى النوع العام serde_json::Value. هذا مشابه لـ serde_json::Value في Python أو object في JavaScript:
use serde_json::Value;
fn main() { let data = r#" { "name": "Rust", "year": 2015, "features": ["safe", "fast", "concurrent"] }"#;
let parsed: Value = serde_json::from_str(data).expect("خطأ في تحليل JSON"); println!("الاسم: {}", parsed["name"]); println!("السنة: {}", parsed["year"]); println!("الميزة الأولى: {}", parsed["features"][0]);}النوع Value يمكن أن يكون: Null، Bool، Number، String، Array أو Object. هذا مناسب للنمذجة الأولية، لكن بالنسبة لكود الإنتاج (production) من الأفضل استخدام الكتابة الصارمة (strict typing).
تسلسل وإلغاء تسلسل الهياكل (Structs)
القوة الرئيسية لـ Serde هي التحويل التلقائي بين هياكل Rust و JSON. دعنا نرى ذلك في مثال:
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]struct User { id: u32, name: String, email: String, active: bool,}
fn main() { // إلغاء التسلسل (JSON -> Rust) let json_str = r#"{"id":1,"name":"أليكسي","email":"alex@example.com","active":true}"#; let user: User = serde_json::from_str(json_str).unwrap(); println!("المستخدم: {:?}", user);
// التسلسل (Rust -> JSON) let new_user = User { id: 2, name: String::from("ماريا"), email: String::from("maria@example.com"), active: false, }; let json_output = serde_json::to_string_pretty(&new_user).unwrap(); println!("JSON:{}", json_output);}لاحظ استخدام to_string_pretty — فهو يقوم بتنسيق JSON مع مسافات بادئة لسهولة القراءة. للإنتاج، استخدم to_string (بدون مسافات إضافية).
العمل مع الهياكل المتداخلة
غالبًا ما يحتوي JSON على كائنات ومصفوفات متداخلة. يتعامل Serde مع هذا بسهولة:
#[derive(Serialize, Deserialize)]struct Project { name: String, languages: Vec<String>, contributors: Vec<Contributor>,}
#[derive(Serialize, Deserialize)]struct Contributor { username: String, contributions: u32,}
fn main() { let project_json = r#" { "name": "Serde", "languages": ["Rust", "Python", "C++"], "contributors": [```