مكتبة once_cell في Rust: التهيئة البطيئة والخلايا ذات الاستخدام الواحد
ما هي ولماذا تحتاجها؟
مكتبة once_cell هي واحدة من أشهر وأهم المكتبات في نظام Rust البيئي، وهي مصممة لتطبيق نمط التهيئة البطيئة (lazy initialization) وإنشاء الخلايا ذات الاستخدام الواحد (once cells). توفر المكتبة نوعين رئيسيين: OnceCell و Lazy، واللذان يحلان مشكلة أساسية وهي تأجيل إنشاء قيمة يتم تهيئتها مرة واحدة فقط عند أول استخدام.
لماذا تحتاج هذا؟ في Rust، كما في أي لغة أخرى، غالباً ما نواجه مواقف يكون فيها إنشاء كائن معين عملية مكلفة (مثل قراءة ملف إعدادات، إنشاء اتصال بقاعدة بيانات، تحميل قاموس كبير). إذا لم يكن هذا الكائن مطلوباً فور تشغيل البرنامج، بل قد يكون ضرورياً فقط في ظروف معينة، يمكن تأجيل تهيئته. تقوم once_cell بذلك بأمان وكفاءة، وتضمن أن التهيئة تحدث مرة واحدة فقط، حتى في حالة الوصول المتزامن من عدة خيوط.
قبل ظهور once_cell في المكتبة القياسية لـ Rust (منذ الإصدار 1.70.0 ظهر std::cell::OnceCell و std::sync::OnceLock)، كانت هذه المكتبة هي المعيار الفعلي للتهيئة البطيئة. ولا تزال ذات صلة حتى اليوم بفضل نضجها ومجموعة الوظائف الواسعة والتوافق العكسي. توفر المكتبة ليس فقط الإصدارات الآمنة للخيوط (sync)، بل أيضاً الإصدارات أحادية الخيط (unsync)، مما يسمح بتجنب الحمل الإضافي للمزامنة حيثما لا تكون هناك حاجة إليها.
التثبيت
لاستخدام once_cell، أضفها إلى تبعيات مشروعك في ملف Cargo.toml:
[dependencies]
once_cell = "1.20"
أو قم بتنفيذ الأمر التالي:
cargo add once_cell
بعد ذلك، يمكنك استيراد الأنواع المطلوبة:
use once_cell::sync::{OnceCell, Lazy};
// أو للاستخدام أحادي الخيط:
use once_cell::unsync::{OnceCell as UnsyncOnceCell, Lazy as UnsyncLazy};
بداية سريعة
مثال عملي بسيط باستخدام Lazy للتهيئة البطيئة لمتغير ثابت:
use once_cell::sync::Lazy;
use std::collections::HashMap;
// سيتم تهيئة المتغير الثابت فقط عند أول استخدام
static CONFIG: Lazy<HashMap<String, String>> = Lazy::new(|| {
println!("جارٍ تهيئة الإعدادات...");
let mut map = HashMap::new();
map.insert("host".to_string(), "localhost".to_string());
map.insert("port".to_string(), "8080".to_string());
map
});
fn main() {
// أول وصول — تتم التهيئة هنا
println!("المضيف: {}", CONFIG.get("host").unwrap());
// ثاني وصول — لا تتم التهيئة، يتم استخدام القيمة المخزنة مؤقتاً
println!("المنفذ: {}", CONFIG.get("port").unwrap());
}
مخرجات البرنامج:
جارٍ تهيئة الإعدادات...
المضيف: localhost
المنفذ: 8080
الدوال والطرق الأساسية
دعنا نستعرض 8 دوال وطرق رئيسية في مكتبة once_cell مع أمثلة استخدام.
1. OnceCell::new()
التوقيع: pub const fn new() -> OnceCell<T>
الوظيفة: تنشئ خلية جديدة فارغة لا تحتوي على قيمة بعد.
use once_cell::sync::OnceCell;
let cell: OnceCell<i32> = OnceCell::new();
assert!(cell.get().is_none()); // الخلية فارغة
2. OnceCell::set()
التوقيع: pub fn set(&self, value: T) -> Result<(), T>