الهياكل والتعدادات في Rust: نمذجة بيانات المصنع
الهياكل: أنواع بيانات مخصصة
الهياكل (Structs) تتيح لك تجميع بيانات مرتبطة في نوع واحد ذي معنى. بدلاً من تمرير عشرات المتغيرات المنفصلة، تُنشئ نوعاً يصف الكيان بالكامل.
// تعريف هيكل لمستشعر صناعي
struct Sensor {
id: u32,
name: String,
unit: String,
last_reading: f64,
is_active: bool,
}
fn main() {
// إنشاء مستشعر جديد
let temp_sensor = Sensor {
id: 101,
name: String::from("مستشعر حرارة الفرن"),
unit: String::from("°C"),
last_reading: 85.3,
is_active: true,
};
println!("المستشعر {}: {} = {} {}",
temp_sensor.id, temp_sensor.name,
temp_sensor.last_reading, temp_sensor.unit);
}
كتل impl: إضافة سلوك
كتل impl تربط الدوال بالهيكل، فيصبح للنوع سلوك خاص به.
struct Sensor {
id: u32,
name: String,
unit: String,
last_reading: f64,
is_active: bool,
}
impl Sensor {
// دالة منشئة (لا تأخذ self)
fn new(id: u32, name: &str, unit: &str) -> Self {
Sensor {
id,
name: String::from(name),
unit: String::from(unit),
last_reading: 0.0,
is_active: true,
}
}
// هل القراءة في النطاق الحرج؟
fn is_critical(&self) -> bool {
self.last_reading > 100.0 || self.last_reading < -20.0
}
// تحديث القراءة
fn update_reading(&mut self, value: f64) {
self.last_reading = value;
}
}
fn main() {
let mut sensor = Sensor::new(1, "ضغط الخط الرئيسي", "bar");
sensor.update_reading(112.5);
if sensor.is_critical() {
println!("⚠ تحذير: {} في حالة حرجة!", sensor.name);
}
}
هياكل الصف والهياكل الفارغة
هياكل الصف (Tuple Structs) تُعطي اسماً لمجموعة قيم بدون تسمية الحقول. الهياكل الفارغة (Unit Structs) تُمثّل حالة بدون بيانات.
// هياكل صف: تُغلّف قيمة واحدة بنوع ذي معنى
struct Temperature(f64);
struct Pressure(f64);
struct Voltage(f64);
// الهيكل الفارغ: يمثّل حالة بدون بيانات
struct Disconnected;
fn main() {
let temp = Temperature(95.2);
let pressure = Pressure(3.5);
// النوع يمنعك من الخلط بين الحرارة والضغط عن طريق الخطأ
// check_temperature(pressure); // خطأ في الترجمة!
println!("الحرارة: {} درجة", temp.0);
println!("الضغط: {} بار", pressure.0);
}
التعدادات: أنواع بمتغيرات
التعدادات (Enums) تصف قيمة يمكن أن تكون واحدة من عدة حالات محددة. هذا مثالي لنمذجة حالات الآلات في المصنع.
enum MachineState {
Running,
Idle,
Error(String),
Maintenance { until: String },
}
fn describe_state(state: &MachineState) {
match state {
MachineState::Running => println!("الآلة تعمل بشكل طبيعي"),
MachineState::Idle => println!("الآلة في وضع الخمول"),
MachineState::Error(msg) => println!("خطأ: {}", msg),
MachineState::Maintenance { until } => {
println!("صيانة حتى: {}", until);
}
}
}
التعدادات مع بيانات: قوة Rust الخارقة
كل متغير في التعداد يمكن أن يحمل بيانات مختلفة تماماً. هذه ميزة قوية لا تتوفر في معظم اللغات.
// كل نوع إنذار يحمل بيانات مختلفة
enum AlarmType {
HighTemperature { current: f64, threshold: f64 },
LowPressure(f64),
CommunicationLost,
CustomAlert(String, u8), // رسالة + مستوى الخطورة
}
fn alarm_priority(alarm: &AlarmType) -> u8 {
match alarm {
AlarmType::HighTemperature { current, threshold }
if *current > threshold * 1.5 => 1, // أولوية قصوى
AlarmType::HighTemperature { .. } => 2,
AlarmType::LowPressure(_) => 2,
AlarmType::CommunicationLost => 3,
AlarmType::CustomAlert(_, level) => *level,
}
}
match مع التعدادات: معالجة شاملة
المُترجم يُجبرك على معالجة كل حالة ممكنة. لا يمكنك نسيان حالة واحدة.
enum ProductionLine {
Active { speed: f64 },
Paused,
Stopped(String), // سبب التوقف
}
fn handle_line(line: &ProductionLine) -> String {
// إذا أضفت متغيراً جديداً ونسيت معالجته هنا
// المترجم سيرفض الترجمة!
match line {
ProductionLine::Active { speed } if *speed > 90.0 => {
String::from("الخط يعمل بسرعة عالية")
}
ProductionLine::Active { speed } => {
format!("الخط يعمل بسرعة {}%", speed)
}
ProductionLine::Paused => String::from("الخط متوقف مؤقتاً"),
ProductionLine::Stopped(reason) => {
format!("الخط متوقف: {}", reason)
}
}
}
مثال عملي: نظام إنذارات المصنع
نجمع الهياكل والتعدادات معاً لبناء نظام إنذارات كامل.
struct Alarm {
sensor_id: u32,
alarm_type: AlarmType,
timestamp: String,
acknowledged: bool,
}
enum AlarmType {
OverTemperature(f64),
UnderPressure(f64),
VibrationExceeded { axis: String, value: f64 },
DeviceOffline,
}
impl Alarm {
fn severity(&self) -> &str {
match &self.alarm_type {
AlarmType::OverTemperature(t) if *t > 150.0 => "حرج",
AlarmType::OverTemperature(_) => "تحذير",
AlarmType::VibrationExceeded { value, .. } if *value > 10.0 => "حرج",
AlarmType::DeviceOffline => "تحذير",
_ => "معلومة",
}
}
fn describe(&self) -> String {
match &self.alarm_type {
AlarmType::OverTemperature(t) =>
format!("حرارة مرتفعة: {}°C", t),
AlarmType::UnderPressure(p) =>
format!("ضغط منخفض: {} bar", p),
AlarmType::VibrationExceeded { axis, value } =>
format!("اهتزاز محور {}: {} mm/s", axis, value),
AlarmType::DeviceOffline =>
String::from("الجهاز غير متصل"),
}
}
}
fn main() {
let alarms = vec![
Alarm {
sensor_id: 101,
alarm_type: AlarmType::OverTemperature(165.0),
timestamp: String::from("2026-04-14 08:30"),
acknowledged: false,
},
Alarm {
sensor_id: 205,
alarm_type: AlarmType::DeviceOffline,
timestamp: String::from("2026-04-14 08:45"),
acknowledged: false,
},
];
for alarm in &alarms {
println!("[{}] مستشعر {} - {} ({})",
alarm.timestamp, alarm.sensor_id,
alarm.describe(), alarm.severity());
}
}
الخلاصة
- الهياكل تجمع بيانات مرتبطة في نوع واحد ذي اسم واضح
- كتل impl تضيف دوالاً وسلوكاً مرتبطاً بالهيكل
- هياكل الصف تُغلّف قيمة بنوع جديد يمنع الخلط
- التعدادات تصف قيمة لها عدة حالات ممكنة
- كل متغير في التعداد يمكنه حمل بيانات مختلفة
- match يُجبرك على معالجة كل حالة — لا تنسى شيئاً
- الجمع بين الهياكل والتعدادات يُنتج نماذج بيانات قوية وآمنة