تعريف الـ Enum وكيفية استخدامه
السلام عليكم ورحمة الله وبركاته
المقدمة
في هذه المقالة سنتعرف على الـ Enum
وما هي الفائدة منه وكيفية استخدامه في البرمجة
والـ Enum
هو اختصار لـ Enumeration
وهو أداة تقدمها لك لغات البرمجة لكي تستطيع تعريف مجموعة من القيم الثابتة تحت مسمى واحد
بمعنى تخيل أنك لديك أنواع مختلفة من الرتب الخاصة بكل موظف لديك، مثل المدير والموظف والمتدرب والمتطوع
يمكنك تخيلها على أنها تصانيف للموظفين بالتالي نحتاج شيء يمثل لنا هذه التصانيف بشكل مقروء وسهل
فمثلًا يمكننا أن نقول أننا سنرمز للمدير بالرقم 1
وللموظف بالرقم 2
وهكذا
هذا حل جيد ومقبول، هذا يعني أننا حين نرى الرقم 1
نعرف أنه يمثل المدير والرقم 2
يمثل الموظف
int EmployeeType = 1;
if (EmployeeType == 1) {
cout << "This is a Manager";
} else if (EmployeeType == 2) {
cout << "This is an Employee";
}
لكن هل تعتقد أن هذا الحل جيد؟
بصراحة لا، لأنك هنا تعتمد أرقام رمزية لتمثيل القيم وهذا يجعل الكود صعب الفهم والتعامل معه
فتخيل أنك لديك 10
أنواع مختلفة من الرتب وتريد ترميزها جميعًا، هل ستقوم بترميز كل رتبة برقم؟
المشكلة الحقيقية هي هل ستتذكر كل رقم يمثل أي رتبة؟
قد تتذكر، لكن سيأتي وقت ستنسى ماذا يمثل الرقم 5
مثلًا أوالرقم 7
وهكذا
لأن الأرقام لا تعطيك معلومات عن القيم التي تمثلها، هي مجرد أرقام لا تعني شيئًا
ستقول لي يمكننا استبدال الأرقام بالـ string
هكذا سيكون الكود أكثر وضوحًا
string EmployeeType = "Manager";
if (EmployeeType == "Manager") {
cout << "This is a Manager";
} else if (EmployeeType == "Employee") {
cout << "This is an Employee";
}
حسنًا هذا حل جيد، لكن هناك مشكلة أخرى، هل تعتقد أنه من الجيد استخدام الـ string
لتمثيل القيم؟
المشكلة هنا أنك قد تخطي الكتابة بالخطأ وتكتب "Manger"
بدلاً من "Manager"
وهكذا أو تكتبها هكذا "manager"
الأخطاء الإملائية هذه قد تحدث وتؤدي إلى مشاكل في البرنامج
هنا يأتي دور الـ Enum
لحل هذه المشكلة، فالـ Enum
يمكنك من تعريف مجموعة من القيم الثابتة تحت مسمى واحد
وهذه المسمى لا يتغير ولا يمكنك تغيير قيمها، وهذا يعني أنك لن تخطئ في كتابة القيمة بالخطأ
كيفية تعريف الـ Enum ؟
جميع اللغات تدعم الـ Enum
ولكن الطريقة تختلف من لغة لأخرى، لكن الفكرة واحدة كما ذكرنا
في لغة الـ C++
يمكنك تعريف الـ Enum
كالتالي
enum EmployeeType {
Manager,
Employee,
Trainee,
Volunteer
};
هنا قمنا بتعريف Enum
بإسم EmployeeType
وقمنا بتعريف 4
قيم ثابتة تحت هذا الإسم وهم Manager
, Employee
, Trainee
, Volunteer
لاحظ أنك هنا تكتب الأنواع كأنها متغيرات وليست string
فهنا كتبنا Manager
وليس "Manager"
الأمر هنا يشبه الـ struct
فهنا نحن أنشأنا نوع جديد من البيانات وهو EmployeeType
وهذا النوع يحتوي على 4
قيم ثابتة داخله
الآن كل ما عليك فعله هو تعريف متغير من نوع EmployeeType
EmployeeType empType;
لاحظ أننا نستخدم الـ EmployeeType
كنوع بيانات جديده مثله مثل int
أو float
أو double
وهكذا
ثم أنشأنا منه متغير جديد بإسم empType
من نوع EmployeeType
ميزة المتغير من نوع Enum
أنه لن يقبل أي قيمة غير القيم الثابتة التي تم تعريفها في الـ Enum
الذي أنشأناه منه
بمعنى أن المتغير empType
طالما هو نوع EmployeeType
فلن يقبل أي قيمة غير Manager
, Employee
, Trainee
, Volunteer
وإذا أخطأت في كتابة القيمة فسينبهك وسيعطيك خطأ في الكود فورًا
empType = Manager; // ✅
empType = Employee; // ✅
empType = Manger; // ❌
empType = manager; // ❌
empType = Hamada; // ❌
قد تقول هل هذا يمكنه فعله مع الـ string
أيضًا؟ سأقول لك أن مشكلة الـ string
هي أنها تقبل أي قيمة تكتبها حتى ولو أخطأت في كتابتها
string empType;
empType = "Manager"; // ✅
empType = "Employee"; // ✅
empType = "Manger"; // ✅
empType = "manager"; // ✅
empType = "Hamada"; // ✅
هنا يمكنك أن ترى أن الـ string
تقبل أي قيمة تكتبها حتى ولو كانت خاطئة، وهذا يعني أنك قد تخطئ في كتابة القيمة بالخطأ
أما الـ Enum
فهو يحميك من هذا الخطأ ويعطيك قيم ثابتة لا يمكنك تغييرها وسينبهك إذا أخطأت في كتابتها
بعد أن قمنا بتعريف Enum
وأسميناه EmployeeType
وأنشأنا متغير من نوعه، يمكنك استخدامه في الشروط والدوال كأي متغير عادي
EmployeeType empType;
empType = Manager;
if (empType == Manager) {
cout << "This is a Manager";
} else if (empType == Employee) {
cout << "This is an Employee";
}
هنا قمنا بتعريف متغير empType
من نوع EmployeeType
وقمنا بتعيين قيمة Manager
له
ثم قمنا بتحقق من قيمة المتغير empType
وطباعة نص معين حسب القيمة التي يحملها المتغير
هذا هو الهدف من الـ Enum
، تعريف مجموعة من القيم الثابتة تحت مسمى واحد
عندما تقوم بطباعة قيمة المتغير empType
ستظهر لك القيمة بشكل رقمي وليس بشكل نصي
بمعنى أنه لن يظهر لك Manager
بل سيظهر لك الرقم 0
لأن Manager
هو القيمة الأولى في الـ Enum
وهكذا
empType = Manager;
cout << empType; // 0
هذا بسبب أنه عندما تقوم بتعريف Enum
فإنه يعطي لك قيم رقمية تبدأ من الصفر وتزيد بمقدار 1
لكل قيمة جديدة
enum EmployeeType {
Manager, // 0
Employee, // 1
Trainee, // 2
Volunteer // 3
};
هنا Manager
يمثل القيمة 0
وEmployee
تمثل القيمة 1
وهكذا
ويمكنك بالطبع تغيير هذه القيم الرقمية وتعيين أي قيمة رقمية تريد بشكل يدوي
enum EmployeeType {
Manager = 1,
Employee = 2,
Trainee = 3,
Volunteer = 4
};
هنا قمنا بتعيين قيم رقمية بشكل يدوي لكل قيمة، فManager
يمثل القيمة 1
وEmployee
تمثل القيمة 2
وهكذا
حل مسألة باستخدام الـ Enum
لنفترض أننا لدينا قاعدة بيانات صغيرة للموظفين ونريد تخزين نوع كل موظف فيها
enum EmployeeType {
Manager,
Employee,
Trainee,
Volunteer
};
struct Employee {
int id;
string name;
EmployeeType type;
};
هنا قمنا بتعريف Enum
بإسم EmployeeType
وقمنا بتعريف 4
قيم ثابتة تحت هذا الإسم
ثم قمنا بتعريف struct
بإسم Employee
وهو يحتوي على 3
متغيرات id
, name
, type
ولاحظ أن المتغير type
من نوع EmployeeType
وهذا يعني أنه لن يقبل سوى القيم الثابتة التي تم تعريفها في الـ Enum
الآن يمكنا إنشاء قائمة بيانات للموظفين وتخزين نوع كل موظف فيها
Employee employees[10] = {
{1, "Ahmed", Manager},
{2, "Mohamed", Employee},
{3, "Ali", Employee},
{4, "Omar", Employee}
{5, "Kamal", Employee},
{6, "Salah", Trainee},
{7, "Mahmoud", Trainee},
{8, "Ashraf", Trainee}
{9, "Khalid", Volunteer},
{10, "Hamada", Volunteer}
};
هنا قمنا بإنشاء أراي من نوع Employee
بإسم employees
وقمنا بتعيين بيانات لكل موظف فيها
ولاحظ كيف أننا استخدمنا الـ Enum
لتعريف نوع كل موظف بشكل واضح وسهل وبدون أخطاء إملائية لأنه كان سينبهنا فورًا
الآن ما رأيك بحل مسألة بسيطة باستخدام الـ Enum
؟
قم باحضار لي الأسماء الأشخاص الذين من نوع Employee
و Volunteer
فقط
for (int i = 0; i < 10; i++) {
if (employees[i].type == Employee || employees[i].type == Volunteer) {
cout << employees[i].name << '\n';
}
}
هنا قمنا بعمل loop
للمرور على عناصر الأراي employees
ونقوم بالتحقق من نوع كل موظف
وإذا كان من نوع Employee
أو Volunteer
فسنقوم بطباعة اسمه
هذا هو الهدف من الـ Enum
، تعريف مجموعة من القيم الثابتة تحت مسمى واحد واستخدامها في البرنامج بشكل سهل وواضح
تخيل لو استخدمنا int
بدلاً من الـ Enum
كيف سيكون الكود؟
كأن الشرط سيكون بهذا الشكل
if (employees[i].type == 1 || employees[i].type == 4) {
cout << employees[i].name << '\n';
}
هل تستطيع أن تعرف ماذا يعني الرقم 1
والرقم 4
؟
إذا كنت تعرف فهذا جيد، لكن هل ستتذكر هذه الأرقام دائمًا؟ بعد اسبوع أو شهر أو سنة؟
وماذا لو استخدمنا string
بدلاً من الـ Enum
؟
كأن الشرط سيكون بهذا الشكل
if (employees[i].type == "Employee" || employees[i].type == "Volunter") {
cout << employees[i].name << '\n';
}
أوه أنا أعتذر لقد في كتابة، لقد كتبت Volunter
بدلاً من Volunteer
دعني أصححها الآن
if (employees[i].type == "Employee" || employees[i].type == "Volunteer") {
cout << employees[i].name << '\n';
}
هل لاحظت الفرق بين الـ Enum
والـ string
؟
الـ string
قد تحتوي على أخطاء إملائية ولن يقوم بتنبيهك بل يجب عليك أنت أن تنتبه لها وقد تجد أن البرنامج لا ينفذ المطلوب بشكل صحيح لمجرد أنك كتبت Volunter
بدلاً من Volunteer
أما الـ Enum
فهو يحميك من هذه الأخطاء وسينبهك إذا أخطأت في كتابتها ولن يقبل سوى القيم الثابتة التي تم تعريفها في الـ Enum
يمكنك هنا بدلًا من الـ if
أن تستخدم الـ switch
لتحقق من نوع كل موظف وجعل الكود أكثر وضوحًا إذا أردت
for (int i = 0; i < 10; i++) {
switch (employees[i].type) {
case Employee:
case Trainee:
cout << employees[i].name << '\n';
}
}
الخاتمة
الـ Enum
أداة قوية ومفيدة في البرمجة تساعدك على تعريف مجموعة من القيم الثابتة تحت مسمى واحد
لتفادي الأخطاء الشائعة وأيضًا لتسهيل فهم الكود وتعامل معه ويجعله مقروء وواضح
فمثلًا هنا في الشرط السابق employees[i].type == Employee || employees[i].type == Volunteer
يمكنك أن تعرف بسهولة أننا نقوم بالتحقق من نوع الموظف إذا كان من نوع Employee
أو Volunteer
الـ Enum
بالطبع مفهوم تدعمه معظم لغات البرمجة ولكن الطريقة تختلف من لغة لأخرى
فمثلًا في لغة الـ Typescript
يمكنك تعريف الـ Enum
بنفس الطريقة الخاصة بالـ C++
enum EmployeeType {
Manager,
Employee,
Trainee,
Volunteer,
}
بصراحة معظم اللغات تدعم شكل الـ Enum
بنفس طريقة الـ C++
أما في لغة php
فالشكل يختلف قليلًا فقط نضيف case
قبل كل نوع
enum EmployeeType {
case Manager;
case Employee;
case Trainee;
case Volunteer;
}
أتمنى أن تكون قد استفدت من هذه المقالة وأن تكون قد فهمت الـ Enum
وكيفية استخدامه في البرمجة
وأن تكون قد فهمت الفائدة منه وكيف يمكنك من تجنب الأخطاء الشائعة وجعل الكود أكثر وضوحًا وسهولة