عبارة التبديل
في برمجة الحاسوب ، تُعدّ عبارة switch آليةً للتحكم في تدفق البرنامج ، حيث تُغيّر مسار التنفيذ بناءً على قيمة تعبير ( أي تقييم متغير ) . تُشبه عبارة switch عبارة if، ولكن بدلاً من التفرع عند القيمتين true أو false فقط، فإنها تتفرع عند أي عدد من القيم. على الرغم من اختلاف صيغة عبارة switch باختلاف لغات البرمجة ، إلا أن معظم اللغات الإجرائية تُوفّر عبارةً بالدلالات الموضحة هنا. يُشار إليها غالبًا بالكلمة المفتاحية switchswitch ، وتستخدم بعض اللغات صيغًا أخرى مثل caseswitch selectو switch و switch inspect.
قيمة
في بعض الأحيان، يُعتبر استخدام عبارة switch أفضل من سلسلة مكافئة من عبارات if-then-else لأنها:
- أسهل للفهم
- وبالتالي، يصبح من الأسهل صيانته: جزئياً على الأقل لأنه ذو عمق ثابت.
- أسهل في تصحيح الأخطاء
- على سبيل المثال، وضع نقاط توقف على التعليمات البرمجية مقابل جدول الاستدعاءات، إذا لم يكن لدى مصحح الأخطاء إمكانية وضع نقاط توقف شرطية.
- أسهل في التحقق
- يتم التعامل مع جميع القيم لأن المترجم يمكنه التحذير إذا لم يتم التعامل مع قيمة ما.
- يمكن تنفيذه بشكل أسرع
- قد يتم تنفيذ التنفيذ الأمثل بشكل أسرع بكثير لأنه غالبًا ما يتم تنفيذه كجدول فرعي . [ 1 ] عند تنفيذه على هذا النحو، فإن عبارة switch تجسد تجزئة مثالية .
- قد يقوم مُصرّف مُحسِّن مثل GCC أو Clang بتحويل عبارة switch إما إلى جدول تفرع أو بحث ثنائي . [ 2 ] يسمح جدول التفرع للبرنامج بتحديد الفرع المراد تنفيذه بعملية حسابية واحدة بدلاً من مقارنة القيم في تسلسل. أما البحث الثنائي فيتطلب عددًا لوغاريتميًا من المقارنات، يُقاس بعدد الحالات في عبارة switch. عمومًا، الطريقة الوحيدة لتحديد ما إذا كان الكود قد تم تحسينه بهذه الطريقة هي تحليل مُخرَج المُصرّف، مثل لغة التجميع أو لغة الآلة .
- أقل تعقيدًا
- في مخطط تدفق التحكم ، تتكون عبارة switch من عقدتين (مدخل ومخرج)، بالإضافة إلى حافة واحدة بينهما لكل خيار. في المقابل، تحتوي سلسلة عبارات if-then-else على عقدة إضافية لكل حالة باستثناء الأولى والأخيرة، إلى جانب حافة مقابلة. وبالتالي، يحتوي مخطط تدفق التحكم الناتج لسلاسل عبارات if على عدد أكبر بكثير من العقد، وضعف عدد الحواف تقريبًا، دون إضافة أي معلومات مفيدة.
عناصر
عادةً، تتضمن عبارة التبديل ما يلي:
- فعل
- يبدأ بفعل تحكم مثل
selectالذي يتبعه تعبير غالباً ما يكون اسم متغير؛ تعبير التحكم أو متغير التحكم .
- حالات
- تبدأ كلٌّ من أقسام البدائل المتفرعة اللاحقة بكلمة مفتاحية (مثلاً
case) متبوعةً بقيمة (أو قيم متعددة) بالإضافة إلى التعليمات البرمجية التي تُنفَّذ بناءً على هذه القيمة (أو القيم). في بعض اللغات، مثل PL/I و Rexx ، إذا حُذف تعبير التحكم، فإن كل بديل يبدأ بعبارةwhenتحتوي على تعبير منطقي، ويحدث التطابق عند أول حالة يكون فيها هذا التعبير صحيحًا؛ على غرار بنية if-then-else.
- في لغة ذات سلوك انتقالي، مثل لغة C، ينتهي كل قسم بكلمة مفتاحية (مثل ) إذا كان يجب ألا ينتقل
breakهذا القسم .
- تقصير
- يُسمح عادةً بحالة افتراضية اختيارية، غالبًا عبر كلمة مفتاحية مثل
default`true` أوotherwise`false` أو `elsefalse`. ينتقل التحكم إلى هذا القسم عندما لا تتطابق أي من الحالات الأخرى مع تعبير التحكم. في بعض اللغات، مثل C، إذا لم تتطابق أي حالة وتم حذف القسم الافتراضي، فلن يُنفذ الأمر أي شيء، ولكن في لغات أخرى، مثل PL/I، يحدث خطأ.
السقوط من خلال
يوجد نوعان رئيسيان من عبارة التبديل: النوع غير المهيكل الذي يدعم الانتقال التلقائي، والنوع المهيكل الذي لا يدعم ذلك.
في عبارات التبديل المنظمة، كما هو الحال في لغات البرمجة المشابهة لـ Pascal ، ينتقل التحكم من بداية عبارة التبديل إلى الحالة المختارة، وعند نهاية الحالة، ينتقل التحكم إلى نهاية عبارة التبديل. يشبه هذا الشرط الشرط if-then-else ، ولكنه يدعم التفرع بناءً على أكثر من مجرد القيمتين true و false. للسماح بتنفيذ نفس الكود باستخدام قيم متعددة (لتجنب تكرار الكود )، يسمح بناء الجملة بقيم متعددة لكل حالة.
يعمل الأمر switch غير المنظم، كما هو الحال في لغة C (وبشكل أعم في اللغات المتأثرة بأمر goto المحسوب في لغة Fortran)، تمامًا مثل أمر goto . ينتقل التحكم من بداية الأمر switch إلى قسم case، ثم يستمر حتى الوصول إلى عبارة exit أو نهاية الأمر switch. عندما ينتقل التحكم إلى حالة واحدة، ولكنه يستمر إلى الفرع التالي، يُسمى هذا التدفق fall through ، ويسمح بالوصول إلى نفس الكود لقيم متعددة.
يُمكن منع حدوث التجاوز (fall through) بإنهاء الحالة بكلمة مفتاحية (مثلاً break)، ولكن من الأخطاء الشائعة حذف هذه الكلمة سهوًا، مما يُسبب تجاوزًا غير مقصود، وغالبًا ما يؤدي إلى ظهور خطأ برمجي . لذلك، يعتبر الكثيرون هذه الخاصية اللغوية خطيرة، [ 3 ] وغالبًا ما ينتج عن استخدام كود التجاوز تحذير من أداة تحليل جودة الكود مثل lint .
تحتفظ بعض اللغات، مثل جافا سكريبت ، بدلالات الانتقال التلقائي، بينما تستبعدها لغات أخرى أو تقيدها. والجدير بالذكر أنه في لغة سي شارب، يجب إنهاء جميع الكتل بـ ` breakif` أو `if` returnإلا إذا كانت الكتلة فارغة، مما يحد من الانتقال التلقائي فقط عند التفرع من قيم متعددة.
في بعض الحالات، توفر لغات البرمجة خيارًا للتنفيذ التلقائي بعد انتهاء التنفيذ. على سبيل المثال، لا تُفعّل لغة بيرل هذا الخيار افتراضيًا، ولكن قد تُفعّله صراحةً باستخدام continueكلمة مفتاحية، مما يمنع التنفيذ التلقائي غير المقصود. وبالمثل، لا تُفعّل لغة باش هذا الخيار افتراضيًا عند إنهاء التنفيذ باستخدام `;; ، ولكنها تسمح به باستخدام ` أو;& ` بدلاً;;& من ذلك`.
ومن الأمثلة على عبارة التبديل التي تعتمد على الانتقال التلقائي هو جهاز داف .
تقييم التعبير عن الحالة
تسمح بعض اللغات بتعبيرات حالة معقدة (ليست مجرد قيمة ثابتة)، مما يتيح سلوك تفرع أكثر ديناميكية. هذا الأمر يحظر بعض تحسينات المُصرّف، لذا فهو أكثر شيوعًا في اللغات الديناميكية حيث تُعطى الأولوية للمرونة على الأداء.
على سبيل المثال، في لغتي PHP و Ruby ، يمكن استخدام ثابت كشرط تحكم، ويتم تنفيذ أول عبارة شرطية تُطابق هذا الثابت. في كود PHP التالي، يُمثل شرط التبديل القيمة "صحيح"، لذا يتم اختيار أول عبارة شرطية صحيحة.
switch ( true ) { case ( $x == 'hello' ) : foo (); break ; case ( $z == 'howdy' ) : break ; }تُعد هذه الميزة مفيدة أيضًا للتحقق من متغيرات متعددة مقابل قيمة واحدة بدلاً من متغير واحد مقابل العديد من القيم.
switch ( 5 ) { case $x : break ; case $y : break ; }يدعم COBOL هذا الشكل أيضًا من خلال عبارته EVALUATE. ويدعم PL/I سلوكًا مشابهًا عن طريق حذف تعبير التحكم، ويتم تنفيذ أول WHENتعبير يتم تقييمه على أنه صحيح.
في لغة روبي، وبفضل طريقة تعاملها مع ===المساواة، يمكن استخدام تعبير الحالة لاختبار نوع المتغير. على سبيل المثال:
في حالة الإدخال، إذا كان من نوع Array ، فسيتم عرض رسالة "الإدخال عبارة عن مصفوفة!". أما إذا كان من نوع Hash، فسيتم عرض رسالة "الإدخال عبارة عن Hash!" .قيمة النتيجة
تدعم بعض اللغات تقييم عبارة التبديل إلى قيمة.
تعبير الحالة
يدعم التعبير الشرطي لغات يعود تاريخها على الأقل إلى لغة ALGOL-W . [ 5 ] في لغة ALGOL-W، كان يتم تقييم تعبير عددي صحيح، والذي بدوره كان يُقيّم التعبير المطلوب من قائمة من التعبيرات:
J := الحالة I من ( 3.14 ، 2.78 ، 44 8.9 ) ؛ A := الحالة DECODE ( C ) - 128 من ( " A " ، " B " ، " C " ، " D " ، " E " ، " F " ) ؛تشمل اللغات الأخرى التي تدعم التعبير عن الحالة SQL و Standard ML و Haskell و Common LISP و Oxygene .
تعبير التبديل
تُقيّم عبارة switch (التي أُضيفت في Java SE 12 ) إلى قيمة. كما يوجد شكل جديد لتسمية الحالة، case L->حيث يكون الجانب الأيمن عبارة عن تعبير واحد. يمنع هذا أيضًا الانتقال التلقائي بين الحالات ويشترط أن تكون جميع الحالات شاملة. في Java SE 13، yieldأُضيفت عبارة switch، وفي Java SE 14 أصبحت عبارات switch ميزة قياسية في اللغة. [ 6 ] [ 7 ] [ 8 ] على سبيل المثال:
int dayCount = switch ( month ) { case JAN , MAR , MAY , JUL , AUG , OCT , DEC -> 31 ; case APR , JUN , SEP , NOV -> 30 ; case FEB -> { if ( year % 400 == 0 ) { yield 29 ; } else if ( year % 100 == 0 ) { yield 28 ; } else if ( year % 4 == 0 ) { yield 29 ; } else { yield 28 ; } } };يدعم روبي هذه الدلالات أيضاً. على سبيل المثال:
catfood = case when cat.age < = 1 junior when cat.age > 10 senior else normal endمعالجة الاستثناءات
تُطبّق العديد من لغات البرمجة شكلاً من أشكال عبارة switch في معالجة الاستثناءات ، حيث إذا حدث استثناء في كتلة برمجية، يتم اختيار فرع منفصل بناءً على نوع الاستثناء. وفي بعض الحالات، يوجد فرع افتراضي في حال عدم حدوث أي استثناء. ومن الأمثلة المبكرة على ذلك لغة Modula-3 ، التي تستخدم صيغة TRY... EXCEPT، حيث EXCEPTيُعرّف كل ... حالةً معينة. وتُستخدم هذه الصيغة أيضاً في لغات Delphi و Scala و Visual Basic .NET .
أمثلة
ج
الكود التالي هو عبارة عن جملة switch في لغة C. إذا ageكانت قيمة المتغير 1، فسيتم إخراج "أنت واحد". إذا ageكانت قيمة المتغير 3، فسيتم إخراج "أنت ثلاثة. أنت ثلاثة أو أربعة". تتصرف جمل switch في لغة C++ بنفس طريقة عملها في لغة C.
#include <stdio.h>void printAge ( unsigned int age ) { switch ( age ) { case 0 : printf ( "أنت حديث الولادة!" ); break ; case 1 : printf ( "أنت في السنة الأولى." ); break ; case 2 : printf ( "أنت في السنتين." ); break ; case 3 : printf ( "أنت في الثلاث سنوات." ); case 4 : printf ( "أنت في الثلاث أو الأربع سنوات." ); break ; default : printf ( "أنت أكبر من 4 سنوات!" ); } }ابتداءً من إصدار C2Y ، تدعم عبارات التبديل تحديد نطاق من الحالات المراد رصدها. ظهرت هذه الميزة لأول مرة كإضافة لمترجم GCC للغة C.
#include <stddef.h> #include <stdio.h> #include <uchar.h>void writeUnicode ( char32_t c ) { switch ( c ) { // يطابق أي قيمة بين [0, 0x7F] شاملة case 0 ... 0x7F : putchar ( c ); break ; // يطابق أي قيمة بين [0x80, 0x7FF] شاملة case 0x80 ... 0x7FF : putchar ( 0xC0 + c >> 6 ); putchar ( 0x80 + c & 0x3f ); break ; // يطابق أي قيمة بين [0x800, 0xFFFF] شاملة case 0x800 ... 0xFFFF : putchar ( 0xE0 + c >> 12 ); putchar ( 0x80 + ( c >> 6 ) & 0x3f ); putchar ( 0x80 + ( c >> 12 )); break ; default : unreachable (); } }بايثون
يدعم بايثون (بدءًا من الإصدار 3.10.6) الكلمتين المفتاحيتين match`and` case. [ 9 ] [ 10 ] [ 11 ] [ 12 ] ولا يسمح بايثون بالتنفيذ المتتالي. على عكس شروط جملة `if`، orلا يمكن استخدام الكلمة المفتاحية `and` للتمييز بين الحالات. case _وهي مكافئة لـ `and` defaultفي لغة C.
letter : str = input ( "أدخل حرفًا: " ) . strip ()[ 0 ] . casefold () match letter : case "a" | "e" | "i" | "o" | "u" : print ( f "الحرف ' { letter } ' هو حرف علة!" ) case "y" : print ( f "قد يكون الحرف ' { letter } ' حرف علة." ) case _ : print ( f "الحرف ' { letter } ' ليس حرف علة!" )باسكال
فيما يلي مثال بلغة باسكال :
case someChar of 'a' : actionOnA ; 'x' : actionOnX ; 'y' , 'z' : actionOnYandZ ; else actionOnNoMatch ; end ;في لهجة أوكسجين من لغة باسكال، يمكن استخدام عبارة التبديل كتعبير:
var i : Integer := case someChar of 'a' : 10 ; 'x' : 20 ; 'y' : 30 ; else - 1 ; end ;نص شل
فيما يلي مثال بلغة سكريبت شل :
case $someChar in a ) actionOnA ; ;; x ) actionOnX ; ;; [ yz ]) actionOnYandZ ; ;; * ) actionOnNoMatch ;; esacمُجمِّع
عبارة التبديل في لغة التجميع :
switch: cmp ah , 00h je a cmp ah , 01h je b jmp swtend ; لا توجد حالة مطابقة أو رمز "افتراضي" هنا a: push ah mov al , 'a' mov ah , 0Eh mov bh , 00h int 10h pop ah jmp swtend ; مكافئ لـ "break" b: push ah mov al , 'b' mov ah , 0Eh mov bh , 00h int 10h pop ah jmp swtend ; مكافئ لـ "break" ... swtend:البدائل
تتضمن بعض البدائل لاستخدام عبارة التبديل ما يلي:
- إذا-ثم-وإلا
- يمكن لسلسلة من عبارات if-then-else الشرطية اختبار كل قيمة من قيم الحالة على حدة. ويمكن تحقيق الانتقال التدريجي باستخدام سلسلة من عبارات if الشرطية، كل منها بدون عبارة else.
- جدول التحكم
- يمكن ترميز منطق عبارة التبديل كجدول تحكم (شكل من أشكال جدول البحث ) يتم فهرسته بواسطة قيم الحالة، وكل قيمة ترمز لما هو موجود في قسم الحالة - كمؤشر دالة أو دالة مجهولة أو آلية مماثلة.
- في لغة لا توفر عبارة switch، مثل Lua ، [ 13 ] يوفر جدول التحكم طريقة لتنفيذ دلالات عبارة switch مع تمكين كفاءة وقت التشغيل التي لا توفرها عبارة if-then-else.
- مطابقة الأنماط
- تُعدّ مطابقة الأنماط وظيفة شبيهة بوظيفة التبديل، وتُستخدم في العديد من لغات البرمجة الوظيفية .
تاريخ
في كتابه " مقدمة في ما وراء الرياضيات" الصادر عام 1952 ، يثبت ستيفن كلين رسميًا أن دالة الحالة (وهي أبسط أشكالها دالة if-then-else) هي دالة تكرارية بدائية ، حيث يُعرّف مفهوم "التعريف بالحالات" على النحو التالي:
#F. الدالة φ معرفة على النحو التالي
- φ(x 1 , ... , x n ) =
- φ 1 (x 1 , ... , x n ) إذا كان Q 1 (x 1 , ... , x n ),
- . . . . . . . . . . . .
- φ m (x 1 , ... , x n ) إذا كان Q m (x 1 , ... , x n ),
- φ m+1 (x 1 , ... , x n ) خلاف ذلك،
حيث Q 1 ، ... ، Q m هي مسندات متنافية (أو φ(x 1 ، ... ، x n ) لها القيمة المعطاة بواسطة البند الأول الذي ينطبق) بدائية تكرارية في φ 1 ، ... ، φ m+1 ، Q 1 ، ... ، Q m+1 .
— ستيفن كلين، [ 14 ]
يقدم كلين برهانًا على ذلك من حيث الدوال المتكررة الشبيهة بالدوال المنطقية "sign-of" sg( ) و "not sign of" ~sg( ) (Kleene 1952:222-223)؛ الأولى تُرجع 1 إذا كان مُدخلها موجبًا و -1 إذا كان مُدخلها سالبًا.
يُضيف بولوس-بورغيس-جيفري ملاحظةً إضافيةً مفادها أن "التعريف بالحالات" يجب أن يكون متنافياً وشاملاً في آنٍ واحد . كما يُقدّمون برهاناً على التكرار البدائي لهذه الدالة (بولوس-بورغيس-جيفري 2002: 74-75).
إن عبارة if-then-else هي أساس شكلية مكارثي : استخدامها يحل محل كل من الاستدعاء الذاتي البدائي وعامل mu .
دعمت مُجمّعات لغة فورتران الأولى عبارة goto المحسوبة للتفرع متعدد الاتجاهات. كما دعمت مُجمّعات لغة ALGOL الأولى نوع بيانات SWITCH الذي يحتوي على قائمة من "التعبيرات التعيينية". ويمكن لعبارة goto أن تُشير إلى متغير switch، ومن خلال توفير فهرس، تتفرع إلى الوجهة المطلوبة. ومع مرور الوقت، تبيّن الحاجة إلى بنية أكثر رسمية متعددة الاتجاهات، بنقطة دخول وخروج واحدة. وقد قدّمت لغات مثل BCPL و ALGOL-W و ALGOL-68 أشكالًا من هذه البنية التي لا تزال مستخدمة في اللغات الحديثة.
انظر أيضاً
مراجع
- ↑ غونثيروث، كورت (27 أبريل 2016). لغة C++ المُحسَّنة . دار نشر أورايلي ميديا. ص 182. ISBN 9781491922033.
- ↑ فلاد لازارينكو. من عبارة التبديل إلى لغة الآلة
- ↑ فان دير ليندن، بيتر (1994). برمجة لغة سي الاحترافية: أسرار لغة سي العميقة ، ص 38. برنتيس هول، إيجل وود كليفس. ISBN 0131774298.
- ↑ منذ الإصدار 4.0 ، الذي صدر في عام 2009.
- ↑ ويرث، نيكلاوس ؛ هوار، سي. أ. ر. (يونيو 1966). "مساهمة في تطوير لغة ALGOL" . مجلة اتصالات رابطة آلات الحوسبة . 9 (6): 413-432 . doi : 10.1145/365696.365702 . S2CID 11901135. تاريخ الاسترجاع : 7 أكتوبر 2020 - عبر رابطة آلات الحوسبة .
- ↑ "JEP 325: تعابير التبديل (معاينة)" . openjdk.java.net . تم الاطلاع عليه بتاريخ 28-04-2021 .
- ↑ "JEP 354: تعابير التبديل (معاينة ثانية)" . openjdk.java.net . تم الاطلاع عليه بتاريخ 28-04-2021 .
- ↑ "JEP 361: تعابير التبديل" . openjdk.java.net . تم الاطلاع عليه بتاريخ 28-04-2021 .
- ↑ جاليندو سالغادو، بابلو. "ما الجديد في بايثون 3.10" . وثائق بايثون 3.10.6 . تم الاطلاع عليه بتاريخ 19 أغسطس 2022 .
- ↑ بوخر، براندت؛ فان روسوم، غيدو (12 سبتمبر 2020). "PEP 634 - مطابقة الأنماط الهيكلية: المواصفات" . مقترحات تحسين بايثون . تم الاطلاع عليه بتاريخ 19 أغسطس 2022 .
- ↑ كون، توبياس ؛ فان روسوم، غيدو (12 سبتمبر 2020). "PEP 635 - مطابقة الأنماط الهيكلية: الدافع والأساس المنطقي" . مقترحات تحسين بايثون . تم الاسترجاع في 19 أغسطس 2022 .
- ↑ مويسيت، دانيال ف. "PEP 636 - مطابقة الأنماط الهيكلية: دليل تعليمي" . مقترحات تحسين بايثون . تم الاسترجاع في 19 أغسطس 2022 .
- ↑ عبارة التبديل في لغة لوا
- ↑ "التعريف من خلال الحالات"، كلين 1952:229
للمزيد من القراءة
- ستيفن كلين ، 1952 (الطبعة العاشرة المعاد طباعتها عام 1991)، مقدمة في ما وراء الرياضيات ، دار نشر نورث هولاند، أمستردام، هولندا، رقم ISBN 0-7204-2103-9
- جورج بولوس ، وجون بورغيس ، وريتشارد جيفري ، 2002، الحوسبة والمنطق: الطبعة الرابعة ، مطبعة جامعة كامبريدج، كامبريدج، المملكة المتحدة، رقم ISBN 0-521-00758-5غلاف ورقي. انظر الصفحتين 74-75.
- البنى الشرطية
