تكوين التطبيقات بلغة Rust: مكتبتا config و dotenv

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

تكوين تطبيقات Rust: مكتبتا config و dotenv



أي تطبيق حديث يحتاج إلى نظام تكوين مرن: إعدادات قاعدة البيانات، مفاتيح API، منافذ الخادم، مستويات التسجيل وغيرها من المعلمات. في نظام Rust البيئي، توجد أدوات قوية لهذا الغرض — كريتات config و dotenv. تسمح بدمج الإعدادات من مصادر مختلفة (ملفات، متغيرات بيئة، وسائط سطر الأوامر) في بنية واحدة آمنة من حيث النوع.



لماذا نحتاج إلى مكتبة منفصلة؟

Rust هي لغة ذات كتابة ثابتة قوية. قراءة السلاسل النصية ببساطة من std::env::var() تؤدي إلى العديد من الفحوصات والتحويلات اليدوية. مكتبة config تؤتمت هذه العملية:

  • دعم الصيغ: YAML، JSON، TOML، HJSON، INI، RON
  • بنية هرمية للإعدادات مع إمكانية التجاوز
  • إلغاء التسلسل تلقائياً إلى بنى مخصصة عبر serde
  • دمج عدة مصادر مع أولويات (ملف < env < CLI)


التثبيت

أضف إلى Cargo.toml:

[dependencies]config = "0.14"serde = { version = "1.0", features = ["derive"] }dotenv = "0.15"


مثال أساسي: القراءة من ملف و env

لننشئ بنية لتكوين التطبيق:

use serde::Deserialize;use config::Config;

#[derive(Debug, Deserialize)]struct AppConfig { server: ServerConfig, database: DatabaseConfig,}

#[derive(Debug, Deserialize)]struct ServerConfig { host: String, port: u16, workers: u8,}

#[derive(Debug, Deserialize)]struct DatabaseConfig { url: String, pool_size: u32,}

fn main() -> Result<(), config::ConfigError> { // تحميل التكوين let config = Config::builder() .add_source(config::File::with_name("config/default")) .add_source(config::Environment::with_prefix("APP")) .build()?;

let app_config: AppConfig = config.try_deserialize()?; println!("{:#?}", app_config); Ok(())}


ملف config/default.toml:

[server]host = "127.0.0.1"port = 8080workers = 4

[database]url = "postgres://localhost/mydb"pool_size = 10


متغيرات البيئة ذات البادئة APP_ تتجاوز القيم من الملف. على سبيل المثال، APP_DATABASE__URL سيغير رابط قاعدة البيانات.



العمل مع dotenv

لتسهيل التطوير، غالباً ما يُستخدم ملف .env. كريت dotenv يقوم بتحميله إلى متغيرات البيئة قبل تهيئة config:

use dotenv::dotenv;

fn main() { dotenv().ok(); // تحميل .env // ثم تهيئة config كما في المثال أعلاه}


محتوى .env:

APP_SERVER__PORT=3000APP_DATABASE__POOL_SIZE=20


سيناريو متقدم: عدة مصادر

المشاريع الحقيقية تتطلب دمج الإعدادات من أماكن مختلفة. config يسمح بتحديد سلسلة من المصادر ذات الأولوية:

let config = Config::builder()    // الإعدادات الأساسية (أولوية منخفضة)    .add_source(config::File::with_name("config/default"))    // تجاوز لبيئة معينة    .add_source(config::File::with_name(&format!("config/{}", env::var("APP_ENV").unwrap_or("development"))))    // متغيرات البيئة (أولوية متوسطة)    .add_source(config::Environment::with_prefix("APP"))    // وسائط سطر الأوامر (أولوية عالية)    .add_source(config::File::from(std::env::args().nth(1).unwrap_or_default()))    .build()?;


أفضل الممارسات

  • استخدم البادئات لمتغيرات البيئة لتجنب التعارض مع المتغيرات النظامية

توصيات