ใช้ดำเนินการต่อในคำสั่งสวิตช์


91

ฉันต้องการข้ามจากตรงกลางของswitchคำสั่งไปยังคำสั่งวนซ้ำในรหัสต่อไปนี้:

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        break;
    default:
        // get another something and try again
        continue;
    }
    // do something for a handled something
    do_something();
}

วิธีนี้ใช้ได้continueหรือไม่ มีcontinueงบโดยไม่สนใจswitchงบ? C และ C ++ แตกต่างกันในพฤติกรรมของพวกเขาที่นี่หรือไม่?


ความคิดของคุณคือดี do_something()แต่ห่วงดังกล่าวข้างต้นจะไม่ดำเนินการ
antik

5
แม้ว่าการควบคุมจะไปถึงกรณี A หรือกรณี B?
Alexander Poluektov

18
ฉันจะบอกว่า antik ผิดเกี่ยวกับเรื่องนั้น ในกรณีของ A หรือ B do_something () จะดำเนินการ โดยค่าเริ่มต้นจะประกันตัว
Antony Woods

3
@acron นั่นคือพฤติกรรมที่ตั้งใจไว้
Matt Joiner

1
ฉันคิดว่าสิ่งนี้ดูน่าสงสัยและสับสนมากกว่าดังนั้นจึงเป็นอันตรายมากกว่าไฟล์goto.
phoeagon

คำตอบ:


57

เป็นเรื่องปกติcontinueคำสั่งนั้นเกี่ยวข้องกับการวนรอบและรหัสของคุณควรเทียบเท่ากับ (หลีกเลี่ยงคำสั่งกระโดดดังกล่าว):

while (something = get_something()) {
    if (something == A || something == B)
        do_something();
}

แต่ถ้าคุณคาดหวังที่breakจะออกจากลูปตามที่ความคิดเห็นของคุณแนะนำ (มักจะลองอีกครั้งกับสิ่งอื่นจนกว่าจะประเมินว่าเป็นเท็จ) คุณจะต้องมีโครงสร้างที่แตกต่างออกไป

ตัวอย่างเช่น:

do {
    something = get_something();
} while (!(something == A || something == B));
do_something();

2
'เทียบเท่า' ในความหมายเท่านั้น รหัสที่คอมไพเลอร์สร้างขึ้นนั้นแตกต่างกันมาก ด้วยคำสั่งสวิตช์คอมไพลเลอร์สามารถสร้างตารางกระโดดซึ่งหลีกเลี่ยงการเปรียบเทียบหลายรายการและเร็วกว่าการเปรียบเทียบกับแต่ละองค์ประกอบ 1 ต่อ 1
chacham15

@ chacham15 ทำไมคอมไพเลอร์ไม่สามารถสร้างรหัสเดียวกันสำหรับทั้งสองได้
วาการ์

คำสั่งสวิตช์ @avakar สร้างตารางกระโดดในขณะที่การแสดงอื่น ๆ เป็นชุดของการประเมินเชิงตรรกะ google jump table สำหรับข้อมูลเพิ่มเติม
chacham15

@ chacham15 อะไรที่ป้องกันไม่ให้คอมไพเลอร์สร้างตารางกระโดดสำหรับคำสั่ง if สองชุดหรือชุดของการประเมินเชิงตรรกะสำหรับสวิตช์
วาการ์

1
คำสั่งสวิตช์ @avakar กำหนดให้เคสเป็นค่าคงที่เนื่องจากไม่ใช่กรณีที่มีคำสั่ง if จึงไม่สามารถทำการปรับให้เหมาะสมเหมือนกันได้ (หมายเหตุ: ฉันกำลังพูดในกรณีทั่วไปเป็นไปได้ตามข้อกำหนดบางประการ (เช่นค่า const เท่านั้น ตัวดำเนินการเชิงตรรกะบางตัวเท่านั้น ฯลฯ ) เพื่อทำการปรับให้เหมาะสม แต่ขึ้นอยู่กับคอมไพเลอร์และ YMMV)
chacham15

21

ใช่ไม่เป็นไร - เหมือนกับการใช้ในifแถลงการณ์ แน่นอนว่าคุณไม่สามารถใช้ a breakเพื่อแยกวงออกจากภายในสวิตช์ได้


แต่ifไม่มีผลต่อพฤติกรรมของcontinueหรือbreak. คุณหมายถึงมันเหมือนกันยังไง?
Matt Joiner

@ แมทฉันหมายความว่ามันจะวนซ้ำในทั้งสองกรณี

1
@ นีลโอเคสับสนหลีกเลี่ยง
Matt Joiner

1
@ KiJéyฉันไม่พบข้อมูลอ้างอิงใด ๆ สำหรับสิ่งนี้และในหลายปีของการเขียนโปรแกรม C ฉันไม่เคยเห็นคอมไพเลอร์ใดที่รองรับสิ่งนี้ ... คุณพบสิ่งนี้ที่ไหนในโลก
arjunyg

2
ว้าวขอโทษฉันเห็นสิ่งนี้ใน PHP คิดว่ามันเป็นแบบเก่า แต่ปรากฎว่ามันเป็นแค่ PHP ...
Ki Jéy

15

ใช่ดำเนินการต่อจะถูกละเว้นโดยคำสั่งสวิตช์และจะไปที่เงื่อนไขของลูปที่จะทดสอบ ฉันต้องการแบ่งปันสารสกัดนี้จากการอ้างอิงภาษาการเขียนโปรแกรม C โดย Ritchie:

continueคำสั่งที่เกี่ยวข้องกับbreakแต่น้อยมักจะใช้; มันทำให้เกิดการย้ำต่อไปของการปิดล้อมfor, whileหรือdoวงที่จะเริ่มต้น ในwhileและdoหมายความว่าส่วนการทดสอบจะดำเนินการทันที ในการforควบคุมจะผ่านไปยังขั้นตอนการเพิ่ม

คำสั่งต่อใช้กับลูปเท่านั้นไม่ใช่กับswitchคำสั่ง continueภายในswitchภายในห่วงทำให้เกิดการย้ำห่วงต่อไป

ฉันไม่แน่ใจเกี่ยวกับเรื่องนี้สำหรับ C ++


8

ถูกต้องตามหลักไวยากรณ์และถูกต้องตามโวหาร

สไตล์ที่ดีต้องมีทุกcase:คำพูดควรลงท้ายด้วยข้อใดข้อหนึ่งต่อไปนี้:

 break;
 continue;
 return (x);
 exit (x);
 throw (x);
 //fallthrough

นอกจากนี้ตามcase (x):ทันทีด้วย

 case (y):
 default:

ได้รับอนุญาต - รวมหลายกรณีที่มีผลเหมือนกันทุกประการ

อะไรก็ได้ที่เป็นผู้ต้องสงสัยที่จะเป็นความผิดพลาดเช่นเดียวif(a=4){...} แน่นอนคุณต้องล้อมรอบวง ( while, for, do...while) สำหรับcontinueการทำงาน มันจะไม่วนกลับไปที่case()คนเดียว แต่โครงสร้างเช่น:

while(record = getNewRecord())
{
    switch(record.type)
    {
        case RECORD_TYPE_...;
            ...
        break;
        default: //unknown type
            continue; //skip processing this record altogether.
    }
    //...more processing...
}

...ไม่เป็นไร.


2
ขออภัยสำหรับการเนโครโพสต์ แต่ฉันจะเพิ่มว่าการโทรไปexitมักจะเป็นเรื่องดีที่จะยุติกรณีสวิตช์ด้วย
Vality

1
ฉันจะได้ดร. แฟรงเกนสไตน์ทั้งหมดที่นี่และยังชี้ให้เห็นว่าdefault:ไม่จำเป็นต้องเป็นรายการสุดท้าย / ล่างสุด - ตามที่คำถามนี้ชี้ให้เห็น ...
SlySven

1
@SlySven: ตามหลักแล้วมันไม่ได้ แต่ถ้าคุณไม่มีเหตุผลที่ดีที่จะไม่ทำให้มันอยู่ได้นานก็ทำให้มันอยู่ได้นาน มักจะสับสนหากใช้ที่อื่น
SF.

1
@SF. ฉันสามารถจินตนาการได้อย่างง่ายดายว่ากรณีใดที่ควรdefault:พิจารณากรณีแรกแทนที่จะเป็นกรณีสุดท้าย เช่น "ทำสิ่งนี้เว้นแต่คุณจะได้รับค่าที่ผิดปกติต่อไปนี้ซึ่งควรได้รับการจัดการดังนี้"
Ruslan

5

แม้ว่าจะถูกต้องในทางเทคนิคการกระโดดทั้งหมดเหล่านี้ทำให้ขั้นตอนการควบคุมไม่ชัดเจน - โดยเฉพาะcontinueคำสั่ง

ฉันจะใช้กลอุบายนี้เป็นทางเลือกสุดท้ายไม่ใช่วิธีแรก

เกี่ยวกับ

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        do_something();
    }        
}

สั้นกว่าและทำงานได้ชัดเจนยิ่งขึ้น


1
ขออภัยในความสับสน Alexander รหัสนี้ใช้สำหรับการสาธิตเท่านั้นฉันมีเหตุผลที่ดี (ฉันเชื่อว่า) สำหรับโครงสร้างจริงในรหัสของฉัน
Matt Joiner

2
@Matt: นั่นอาจหมายถึงโครงสร้างที่สับสนยิ่งกว่าเดิม ... :)
ผู้เยี่ยมชม

-2

อาจเป็นเมกะบิตถึงช้า แต่คุณสามารถcontinue 2ใช้ได้

php builds / configs บางตัวจะแสดงคำเตือนนี้:

คำเตือน PHP: สวิตช์กำหนดเป้าหมาย "ดำเนินการต่อ" เทียบเท่ากับ "หยุดพัก" คุณหมายถึงใช้ "ต่อ 2" ใช่ไหม

ตัวอย่างเช่น:

$i = 1;

while ($i <= 10) {
    $mod = $i % 4;
    echo "\r\n out $i";
    $i++;
    switch($mod)
    {
        case 0:
            break;
        case 2:
            continue;
            break;
        default:
            continue 2;
            break;
    }
    echo " is even";
}

สิ่งนี้จะส่งออก:

out 1
out 2 is even
out 3
out 4 is even
out 5
out 6 is even
out 7
out 8 is even
out 9
out 10 is even

ทดสอบด้วย PHP 5.5 ขึ้นไป


3
นี่ไม่ใช่คำถาม PHP
Geoffrey

-4

สวิตช์ไม่ถือเป็นลูปดังนั้นคุณจึงไม่สามารถใช้Continue inside a case statement in switch ...


3
switchคำสั่งอยู่ภายในwhileวงเพื่อให้continueเป็นที่ถูกต้องสมบูรณ์
Rick
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.