ما هو أمر الـ switch في البرمجة ؟

السلام عليكم ورحمة الله وبركاته

وقت القراءة: ≈ 10 دقائق

المقدمة

في هذه المقالة سنتعرف على أمر switch وهي أداة تستخدم لرؤية قيمة معينة وتحديد مسار البرنامج بناءً على هذه القيمة
فمثلًا لديك متغير ما وهذا المتغير قد يتخذ قيم معينة محدد وأنت تعلمها مسبقًا وبناءًا على كل قيمة أنت تريد اتخاذ وتنفيذ بعض الأشياء

فمثلًا متغير يمثل اللغة التي يتحدث بها الشخص، يمكنك استخدام switch لتحديد اللغة وطباعة رسالة معينة بناءً على لغة الشخص

قد تجد بعض الأشخاص يقولون أنه يمكن استخدام if else بدلاً من switch وهذا صحيح لكن switch يكون أكثر تنظيمًا وسهولة في القراءة في حال كانت القيم محدودة
فالـ switch تتعامل مع القيم الثابتة المعروف قيمتها أما if تتعامل مع الشروط

كيف نكتب switch في البرمجة ؟

شكل الـ switch في معظم لغات البرمجة غالبًا ما يكون هكذا

switch (المتغير) {
  case الحالة_1:
    // الكود الذي سيتم تنفيذه إذا كانت قيمة المتغير تساوي الحالة_1
    break;
  case الحالة_2:
    // الكود الذي سيتم تنفيذه إذا كانت قيمة المتغير تساوي الحالة_2
    break;
  // ... إلخ
  // يمكن إضافة المزيد من الحالات حسب الحاجة
  default:
    // الكود الذي سيتم تنفيذه إذا لم تتطابق قيمة المتغير مع أي حالة
}

كما ترى نكتب switch ونضع المتغير التي نريد مقارنة قيمته بين القوسين
ثم نعرف الحالات التي نتوقعها من المتغير بعد كل كلمة case
ونكتب الكود الذي نريد تنفيذه إذا تطابقت قيمة المتغير مع الحالة

ثم ننهي كل حالة بـ break للخروج من الـ switch بعد تنفيذ الحالة المطابقة
لكي لا يتم تنفيذ الحالات التالية بعد تنفيذ الحالة المطابقة

ويمكننا استخدام default لتحديد الكود الذي سيتم تنفيذه إذا لم تتطابق قيمة المتغير مع أي حالة
وسنرى مثالًا على كل هذا في الأمثلة التالية


بعض اللغات تستبدل كلمة switch بكلمة أخرى مثل match
مع بعض الفروقات في الكتابة والاستخدام، ولكن المبدأ العام هو نفسه

match المتغير:
    case الحالة_1:
      # الكود الذي سيتم تنفيذه إذا كانت قيمة المتغير تساوي الحالة_1
    case الحالة_2:
      # الكود الذي سيتم تنفيذه إذا كانت قيمة المتغير تساوي الحالة_2
    case الحالة_3:
      # الكود الذي سيتم تنفيذه إذا كانت قيمة المتغير تساوي الحالة_3
    # ... إلخ
    case _:
    # الكود الذي سيتم تنفيذه إذا لم تتطابق قيمة المتغير مع أي حالة

فمثلًا في لغة Python نستخدم match بدلاً من switch ولاحظ أنه يستخدم case _ بدلاً من default
لاحظ الفرق البسيط في الكتابة ولكن المبدأ العام هو نفسه
وستجد نفس الشيء مع بافي اللغات الأخرى

لذا أخبرتك أن من المهم أن تتعلم المبادئ العامة للبرمجة وليس التفاصيل الدقيقة لكل لغة
عندما اعلمك عن switch أو عن المتغيرات أو عن هذا وذاك ستجد نفس المبدأ في معظم لغات البرمجة
قد تجد تفاصيل صغيرة تختلف ولكن الأساس واحد والهدف واحد

مثال على استخدام switch

لنفترض أننا نريد إرسال رسالة للموظفين بناءً على القسم الذي يعملون فيه
ولدينا هنا كل قسم يعبر عنه برقم فقسم المبيعات هو رقم 1 وقسم الدعم الفني هو رقم 2 وقسم الموارد البشرية هو رقم 3
لاحظ أننا الآن لدينا أرقام ثابتة ومحددة وهذا يجعل switch هو الخيار الأفضل هنا

int employee_department = 2;

switch (employee_department) {
  case 1:
    cout << "إرسال رسالة لقسم المبيعات";
    break;
  case 2:
    cout << "إرسال رسالة لقسم الدعم الفني";
    break;
  case 3:
    cout << "إرسال رسالة لقسم الموارد البشرية";
    break;
  default:
    cout << "قسم غير معروف";
}

هنا كل قسم يعبر عنه برقم بالتالي لنفترض أن لدينا متغير يدعى department يحتوى على رقم القسم الذي يعمل فيه الموظف
بالتالي عندما يدخل البرنامج إلى الـ switch سيجد أن قيمة المتغير department تساوي 2
فسينفذ الحالة المطابقة وهي case 2 وسيتم طباعة الرسالة إرسال رسالة لقسم الدعم الفني
ثم سيخرج من الـ switch بسبب وجود break في النهاية

لنرى مثالًا آخر

string user_language = "ar";

switch (user_language) {
  case "ar":
    cout << "تم اختيار اللغة العربية";
    break;
  case "en":
    cout << "English language selected";
    break;
  case "tr":
    cout << "Türkçe dil seçildi";
    break;
  default:
    cout << "Language not supported";
}

في هذا المثال نقوم بتفقد المتغير user_language وبناءًا على قيمته ننفذ الكود الذي يطابق حالته قيمة المتغير
هنا نحن فقط نطبع رسالة توضح اللغة المختارة
ثم نستخدم break للخروج من الـ switch بعد تنفيذ الحالة المطابقة

قيمة المتغير user_language هنا هي ar لذا سيتم طباعة الرسالة تم اختيار اللغة العربية
وبعد ذلك يتم الخروج من الـ switch بسبب وجود break في نهاية الحالة

تم اختيار اللغة العربية

في لغة C++ الـ switch لا تعمل إلا مع المتغيرات التي من نوع int أو char
لذا الكود السابق لن يعمل في C++ لأن المتغير user_language من نوع string

لكن في معظم اللغات الأخرى يمكنك استخدام switch مع أي نوع من المتغيرات سواء كانت int أو string أو char أو أي نوع آخر
وفي C++ يمكنك استخدام switch مع المتغيرات التي تحتوي على قيم ثابتة مثل int أو char

لذا من أجل استكمال الشرح لنتظاهر أن الـ C++ تدعم switch مع المتغيرات من نوع string
أو نستطيع استكمال الشرح بامثله من لغة TypeScript بدلاً من C++ حاليًا لأنها تدعم switch مع المتغيرات من نوع string

لأن هدفنا في النهاية هو تعلم المفهوم وليس التفاصيل الدقيقة لكل لغة

وبالمناسبة الكود السابق في لغة TypeScript يبدو كالتالي

let user_language: string = 'ar';

switch (user_language) {
  case 'ar':
    console.log('تم اختيار اللغة العربية');
    break;
  case 'en':
    console.log('English language selected');
    break;
  case 'tr':
    console.log('Türkçe dil seçildi');
    break;
  default:
    console.log('Language not supported');
}

لا يوجد أي فرق يذكر كما ترى فقط طريقة طباعة نستخدم هنا console.log بدلاً من cout وهنا لا نفرق بين " و '
لكن تظل الفكرة والمبدأ وأساس الـ switch هو نفسه ثابت
لذا عندما تتعلم المفاهيم العامة للبرمجة ستجد أنك تستطيع التعامل مع معظم لغات البرمجة بسهولة
سأستكمل الشرح بلغة TypeScript لأنها تدعم switch مع المتغيرات من نوع string وهذا يسهل علينا الشرح
وأنت لن تشعر باختلاف كبير

ماذا يحدث إذا نسيت كتابة break ؟

بعض اللغات عندما يتم تنفيذ حالة معينة تظل تنفذ باقي الحالات وتتوقف فقط عندما تجد break
لذا إذا نسيت كتابة break فإن الحالات التالية ستتم تنفيذها أيضًا

فمثلًا في الكود التالي

let user_language: string = 'en';

switch (user_language) {
  case 'ar':
    console.log('تم اختيار اللغة العربية');
  case 'en':
    console.log('English language selected');
  case 'tr':
    console.log('Türkçe dil seçildi');
  default:
    console.log('Language not supported');
}

هنا قمنا بنسيان كتابة break في نهاية كل حالة
وبما أن قيمة المتغير user_language هي en فسيتم طباعة الرسالة English language selected
ثم بسبب عدم وجود break سيتم تنفيذ الحالات التالية أيضًا وسيتم طباعة الرسائل Türkçe dil seçildi و Language not supported

English language selected
Türkçe dil seçildi
Language not supported

حتى الـ default تم طباعة الرسالة الخاصة به بسبب عدم وجود break بعد كل لحالة
لذا عليك الحذر هنا

لكن أحيانًا نتعمد عدم كتابة break لنقوم بتنفيذ حالات متتالية بنفس الكود، كما سنرى تاليًا

دمج حالات الـ switch

أحيانًا ستجد أن هناك حالات متشابهة وتريد تنفيذ نفس الكود لهذه الحالات
فمثلا نريد السماح لطلاب السنة الأولى والثانية فقط بدخول التدريبات الصيفية لكن لا نريد السماح لطلاب السنة الثالثة والرابعة والخامسة

هنا يمكنك دمج حالات الـ switch بدون كتابة break بينهم

let student_year: number = 2;

switch (student_year) {
  case 1:
  case 2:
    console.log('مسموح لك بأخذ التدريب الصيفي');
    break;
  case 3:
  case 4:
  case 5:
    console.log('نأسف لكن غير المسموح لك بأخذ التدريب الصيفي');
    break;
  default:
    console.log('سنة غير معروفة');
}

لاحظ هنا أننا قمنا بدمج حالات السنة الأولى والثانية معًا بدون كتابة break بينهم فقط نكتب case 1: ثم case 2:
وبعد ذلك نكتب الكود الذي نريد تنفيذه لهذه الحالتين
وبعد ذلك نكتب break للخروج من الـ switch بعد تنفيذ الحالة المطابقة

ونفس الشيء فعلناه مع حالات السنة الثالثة والرابعة والخامسة
وفي النهاية كتبنا default للتعامل مع الحالات الأخرى التي لم تتطابق مع أي حالة


في لغة C++ تستطيع عمل نفس الشيء ودمج حالات الـ switch بدون كتابة break بينهم

int student_year = 2;

switch (student_year) {
  case 1:
  case 2:
    cout << "مسموح لك بأخذ التدريب الصيفي";
    break;
  case 3:
  case 4:
  case 5:
    cout << "نأسف لكن غير المسموح لك بأخذ التدريب الصيفي";
    break;
  default:
    cout << "سنة غير معروفة";
}

وأيضًا هناك ميزة موجودة في C++ ومعظم اللغات وليست موجودة في لغة TypeScript
وهي تحديد نطاق للحالات مثل case 1 ... 5: لتحديد نطاق محدد القيم فهنا نقول أنه إذا كانت القيمة بين 1 و 5 فقط سيتم تنفيذ الكود

int student_year = 2;

switch (student_year) {
  case 1 ... 2:
    cout << "مسموح لك بأخذ التدريب الصيفي";
    break;
  case 3 ... 5:
    cout << "نأسف لكن غير المسموح لك بأخذ التدريب الصيفي";
    break;
  default:
    cout << "سنة غير معروفة";
}

لاحظ أن كيف لكل لغة لها مميزات وعيوب تتميز بها عن باقي اللغات الأخر

متى نفضل استخدام switch بدلاً من if else ؟

في العادة يمكن استخدام switch بدلاً من if else في حال كانت القيمة التي نريد مقارنتها ثابتة ومحدودة لكن أحيانًا يكون من الأفضل استخدام if else في حال كنت تريد كتابة شرط كبير لأن switch تتعامل مع القيم الثابتة وليس مع الشروط

فمثلًا هل تستطيع تحويل الكود التالي إلى switch ؟

int student_grade = 70; // درجة الطالب

if (student_grade >= 85)
  cout << "The student grade is A\n";

if (student_grade >= 75)
  cout << "The student grade is B\n";

if (student_grade >= 65)
  cout << "The student grade is C\n";

if (student_grade >= 50)
  cout << "The student grade is D\n";

if (student_grade < 50)
  cout << "The student grade is F\n";

هنا يوجد نطاق كبير من القيم والشروط وهذا يجعل من الصعب استخدام switch هنا
لا أقول مستحيل بل أقول صعب وبعض اللغات قد تمتلك مميزات تجعلها تتعامل مع الشروط لكن بشكل عام هذه الحالة لا يفضل استخدام switch
لذا في حال كانت القيم محدودة وثابتة يمكنك استخدام switch وإلا استخدم if else خصوصًا إذا كانت الشروط كبيرة وغير مترابطة مع بعض

لنرى مثال لنوضح ما أقوله
الآن نريد تنفيذ كود معين بناءًا على فصول السنة
لنعبر عن كل فصل برقم ففصل الشتاء هو 1 والربيع هو 2 والصيف هو 3 والخريف هو 4

int sprint = 3;

switch (sprint) {
  case 1:
    cout << "أنه فصل الشتاء، لنرتدي ملابس دافئة";
    break;
  case 2:
    cout << "أنه فصل الربيع، لنستمتع بالمناظر الجميلة";
    break;
  case 3:
    cout << "أنه فصل الصيف، لنذهب إلى الشاطئ";
    break;
  case 4:
    cout << "أنه فصل الخريف، لنقوم بـ .. اا .. امم بأي شيء ؟";
    break;
  default:
    cout << "فصل غير معروف";
}

ويمكننا تحويل هذا الكود إلى if else بكل سهولة

int sprint = 3;

if (sprint == 1)
  cout << "أنه فصل الشتاء، لنرتدي ملابس دافئة";
else if (sprint == 2)
  cout << "أنه فصل الربيع، لنستمتع بالمناظر الجميلة";
else if (sprint == 3)
  cout << "أنه فصل الصيف، لنذهب إلى الشاطئ";
else if (sprint == 4)
  cout << "أنه فصل الخريف، لنقوم بـ .. اا .. امم بأي شيء ؟";
else
  cout << "فصل غير معروف";

الأمور لغاية الآن جيدة وكود الـ switch كان أوضح ومباشر أكثر عن الـ if else

ولكن لنرى مثالًا آخر به عدة شروط لنرى كيف سيبدو الكود بالـ if else وكيف سيكون بالـ switch

string name = "Ahmed";
int id = 125;

if (id == 125 && name == "Ahmed")
  cout << "Welcome " + name + " in the system";
else if (id != 125 || name != "Ahmed")
  cout << "The ID or the name are wrong";
else
  cout << "Unknown error";

هل تستطيع تحويل هذا الكود إلى switch ؟
الإجابة هي لا لأن switch لا يتعامل مع الشروط والعمليات المعقدة كهذه
بل يتعامل مع القيم الثابتة والمحدودة فقط
ومن غير المنطقي استخدام switch هنا حتى لو كان هناك طرق تحايلية أومميزات في اللغة تسمح بذلك
لكن هذا ليس الهدف من switch

إليك الكود السابق بالـ switch لترى كيف سيكون

string name = "Ahmed";
int id = 125;

switch (id) {
  case 125:
    switch (name) {
      case "Ahmed":
        cout << "Welcome " + name + " in the system";
        break;
      default:
        cout << "The ID or the name are wrong";
    }
    break;
  default:
    cout << "Unknown error";
}

هل تستطيع فهم هذا الكود ؟ قد تستطيع لكن بصعوبة كبيرة لأن هذا ليس الهدف من switch
لذا في حال كانت الشروط معقدة ومتشابكة يفضل استخدام if else وليس switch

في النهاية نحن نريد كتابة كود مقروء وليس سلطة معكرونة


إليك هذا المثال بالـ switch
لنفترض أن يوم الأحد يمثل الرقم 1 والاثنين يمثل الرقم 2 والثلاثاء يمثل الرقم 3 وهكذا

int day = 3;

switch (day) {
  case 1:
  case 2:
  case 3:
  case 4:
  case 5:
    cout << "للآسف يوم عمل"
    break;
  case 6:
  case 7:
    cout << "اجااااازة";
    break;
  default:
    cout << "يوم غير معروف";
}

هنا قمنا بدمج أيام العمل معًا وأيام الإجازة معًا وهذا يجعل الكود أكثر قراءة وسهولة
هل تتخيل كيف سيكون الكود بالـ if else ؟

int day = 3;

if (day == 1 || day == 2 || day == 3 || day == 4 || day == 5)
  cout << "للآسف يوم عمل";
else if (day == 6 || day == 7)
  cout << "اجااااازة";
else
  cout << "يوم غير معروف";

أو

int day = 3;

if (day >= 1 && day <= 5)
  cout << "للآسف يوم عمل";
else if (day == 6 || day == 7)
  cout << "اجااااازة";
else
  cout << "يوم غير معروف";

الكود جيد ولكن الـ switch أفضل من حيث قراءة وسهولة الفهم
نحن نختار ما يناسبنا وما نراه أفضل لنا


أرجوا من كل قلبي أنك لم تفكر في كتابة الكود التالي
ولا احتاج لتفسير كم سوء وقبح الكود التالي

int day = 3;

if (day == 1)
  cout << "للآسف يوم عمل";
else if (day == 2)
  cout << "للآسف يوم عمل";
else if (day == 3)
  cout << "للآسف يوم عمل";
else if (day == 4)
  cout << "للآسف يوم عمل";
else if (day == 5)
  cout << "للآسف يوم عمل";
else if (day == 6)
  cout << "اجااااازة";
else if (day == 7)
  cout << "اجااااازة";
else
  cout << "يوم غير معروف";

الخلاصة

في النهاية الـ switch أداة تستخدم للتحكم في مسار البرنامج بناءًا على قيمة معينة
وتستخدم في حال كانت القيم محدودة وثابتة وليست شروط كبيرة

وفي حال كانت الشروط كبيرة ومعقدة يفضل استخدام if else بدلاً من switch
لأن الـ switch لا يتعامل مع الشروط والعمليات المعقدة كهذه
بل يتعامل مع القيم الثابتة والمحدودة فقط

وفي النهاية نحن نريد كتابة كود مقروء وسهل الفهم
لذا نحن نختار ما يناسبنا وما نراه أفضل لنا من حيث سهولة القراءة والفهم والتعديل المستقبلي
وعوامل كثيرة تحدد وتغير اختياراتنا وليس فقط الـ switch و if else بل في كل مفهوم في البرمجة حتى التي لا تعرفها بعد