สลับคำสั่งกับผลตอบแทน - ความถูกต้องของรหัส


92

สมมติว่าฉันมีรหัสใน C โดยมีโครงสร้างประมาณนี้:

เห็นได้ชัดว่าbreaks ไม่จำเป็นสำหรับรหัสที่จะทำงานอย่างถูกต้อง แต่ดูเหมือนว่าจะเป็นการปฏิบัติที่ไม่ดีถ้าฉันไม่ใส่ให้ฉัน

คุณคิดอย่างไร? ลบออกได้ไหม หรือคุณจะเก็บไว้เพื่อเพิ่ม "ความถูกต้อง"?

คำตอบ:


141

ลบbreakคำสั่ง ซึ่งไม่จำเป็นและบางทีคอมไพเลอร์บางตัวอาจออกคำเตือน"รหัสที่ไม่สามารถเข้าถึงได้"


2
เช่นเดียวกันกับข้อความควบคุมกระโดดแบบไม่มีเงื่อนไขอื่น ๆ เช่นcontinueหรือgoto- เป็นสำนวนที่จะใช้แทนbreak.
caf

32

ฉันจะใช้วิธีที่แตกต่างไปจากเดิมอย่างสิ้นเชิง อย่าส่งกลับมาตรงกลางของวิธีการ / ฟังก์ชัน ให้ใส่ค่าที่ส่งคืนในตัวแปรโลคัลแทนแล้วส่งในตอนท้าย

โดยส่วนตัวแล้วฉันพบว่าสิ่งต่อไปนี้สามารถอ่านได้มากขึ้น:


24
ปรัชญา "ทางออกเดียว" มีความหมายใน C ซึ่งคุณต้องแน่ใจว่าสิ่งต่างๆได้รับการทำความสะอาดอย่างถูกต้อง เมื่อพิจารณาใน C ++ คุณสามารถดึงออกจากฟังก์ชันได้ทุกเมื่อโดยข้อยกเว้นปรัชญาการออกเพียงข้อเดียวไม่ได้มีประโยชน์อย่างแท้จริงใน C ++
Billy ONeal

29
ตามทฤษฎีแล้วนี่เป็นความคิดที่ดี แต่บ่อยครั้งที่ต้องใช้บล็อกควบคุมพิเศษซึ่งอาจขัดขวางการอ่าน
mikerobi

8
เหตุผลหลักว่าทำไมฉันถึงทำแบบนี้ก็คือในฟังก์ชันที่ยาวขึ้นมันง่ายมากที่จะพลาดเวกเตอร์ทางออกเมื่อสแกนผ่านโค้ด อย่างไรก็ตามเมื่อทางออกอยู่ที่จุดสิ้นสุดเสมอคุณจะเข้าใจสิ่งที่เกิดขึ้นได้ง่ายขึ้น
NotMe

7
นั่นคือและส่งคืนบล็อกที่อยู่ตรงกลางของโค้ดเพียงแค่เตือนฉันถึงการละเมิดของ GOTO
NotMe

5
@ คริส: ในฟังก์ชั่นที่ยาวขึ้นฉันเห็นด้วยอย่างยิ่ง - แต่โดยปกติแล้วจะพูดถึงปัญหาที่ใหญ่กว่าดังนั้นจึงเปลี่ยนมัน ในหลาย ๆ กรณีมันเป็นฟังก์ชั่นเล็กน้อยที่กลับมาบนสวิตช์และเป็นที่ชัดเจนว่าจะเกิดอะไรขึ้นดังนั้นอย่าเสียพลังสมองไปกับการติดตามตัวแปรพิเศษ
Stephen

8

โดยส่วนตัวฉันจะลบผลตอบแทนและหยุดพัก ฉันจะใช้คำสั่ง switch เพื่อกำหนดค่าให้กับตัวแปร จากนั้นส่งกลับตัวแปรนั้นหลังคำสั่ง switch

แม้ว่านี่จะเป็นประเด็นที่สามารถโต้แย้งได้ฉันรู้สึกมาตลอดว่าการออกแบบและการห่อหุ้มที่ดีหมายถึงทางเข้าและทางออกทางเดียว การรับประกันตรรกะนั้นง่ายกว่ามากและคุณจะไม่พลาดรหัสการล้างข้อมูลโดยไม่ได้ตั้งใจตามความซับซ้อนของวงจรของฟังก์ชันของคุณ

ข้อยกเว้นประการหนึ่ง: การกลับมาก่อนเวลานั้นไม่เป็นไรหากตรวจพบพารามิเตอร์ที่ไม่ถูกต้องที่จุดเริ่มต้นของฟังก์ชันก่อนที่จะได้รับทรัพยากรใด ๆ


อาจดีสำหรับสิ่งนี้โดยเฉพาะswitchแต่ไม่จำเป็นต้องดีที่สุดโดยทั่วไป สมมติว่าคำสั่ง switch ภายในฟังก์ชันนำหน้าโค้ดอีก 500 บรรทัดซึ่งใช้ได้เฉพาะเมื่อมีบางกรณีtrueเท่านั้น อะไรคือจุดสำคัญของการเรียกใช้รหัสพิเศษทั้งหมดสำหรับกรณีที่ไม่จำเป็นต้องเรียกใช้งาน ไม่ดีกว่าที่จะreturnอยู่ข้างในswitchสำหรับพวกนั้นcase?
Fr0zenFyr

6

หยุดพักไว้ - คุณมีโอกาสน้อยที่จะประสบปัญหาหาก / เมื่อคุณแก้ไขโค้ดในภายหลังหากมีการหยุดพักแล้ว

ต้องบอกว่าหลายคน (รวมทั้งฉัน) ถือว่าเป็นการปฏิบัติที่ไม่ดีที่จะกลับมาจากช่วงกลางของฟังก์ชัน ตามหลักการแล้วฟังก์ชันควรมีจุดเข้าและจุดออกหนึ่งจุด


5

ลบออก มันเป็นสำนวนที่จะกลับมาจากcaseคำสั่งและเป็นเสียง "รหัสที่ไม่สามารถเข้าถึงได้" เป็นอย่างอื่น


5

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


4

ปกติฉันจะเขียนโค้ดโดยไม่มีพวกเขา IMO รหัสตายมีแนวโน้มที่จะบ่งบอกถึงความชุ่ยและ / หรือขาดความเข้าใจ

แน่นอนฉันจะพิจารณาบางสิ่งเช่น:

แก้ไข: แม้จะมีการแก้ไขโพสต์แนวคิดทั่วไปนี้ก็สามารถใช้ได้ดี:

ในบางจุดโดยเฉพาะอย่างยิ่งถ้าค่าอินพุตเบาบาง (เช่น 1, 100, 1000 และ 10,000) คุณต้องการอาร์เรย์แบบกระจัดกระจายแทน คุณสามารถใช้สิ่งนั้นเป็นต้นไม้หรือแผนที่ได้ดีพอสมควร (แต่แน่นอนว่าสวิตช์ยังคงใช้งานได้ในกรณีนี้เช่นกัน)


แก้ไขโพสต์เพื่อแสดงให้เห็นว่าเหตุใดโซลูชันนี้จึงทำงานได้ไม่ดี
houbysoft

@ แก้ไขของคุณ: ใช่ แต่จะต้องใช้หน่วยความจำมากกว่า ฯลฯ IMHO สวิตช์เป็นวิธีที่ง่ายที่สุดซึ่งเป็นสิ่งที่ฉันต้องการในฟังก์ชั่นเล็ก ๆ เช่นนี้ (ใช้เพียงแค่สวิตช์)
houbysoft

3
@houbysoft: ดูให้ดีก่อนสรุปว่าจะใช้หน่วยความจำเพิ่ม สำหรับคอมไพเลอร์ทั่วไปการใช้ "foo" สองครั้ง (เช่น) จะใช้พอยน์เตอร์สองตัวในบล็อกข้อมูลเดียวโดยจะไม่จำลองข้อมูล คุณยังสามารถคาดหวังโค้ดที่สั้นกว่านี้ได้ หากคุณมีค่าซ้ำ ๆจำนวนมากก็มักจะช่วยประหยัดหน่วยความจำโดยรวม
Jerry Coffin

จริง. ฉันจะยังคงยึดติดกับวิธีแก้ปัญหาของฉันแม้ว่ารายการของค่านั้นยาวมากและสวิตช์ก็ดูดีกว่า
houbysoft

1
อันที่จริงคำตอบที่สวยงามและมีประสิทธิภาพยิ่งขึ้นสำหรับปัญหาเช่นนี้เมื่อค่าของสวิตช์อยู่ติดกันและชนิดข้อมูลเป็นเนื้อเดียวกันคือการใช้อาร์เรย์เพื่อหลีกเลี่ยงสวิตช์โดยสิ้นเชิง
Dwayne Robinson

2

ฉันจะบอกว่าลบออกและกำหนดค่าเริ่มต้น: branch


หากไม่มีค่าเริ่มต้นที่เหมาะสมคุณไม่ควรกำหนดค่าเริ่มต้น
Billy ONeal

มีอยู่อันหนึ่งและฉันได้กำหนดไว้ฉันไม่ได้ใส่ไว้ในคำถามแก้ไขเดี๋ยวนี้
houbysoft

2

จะดีกว่าไหมถ้ามีอาร์เรย์ด้วย

และทำreturn arr[something];อย่างไร

หากเป็นเรื่องเกี่ยวกับการปฏิบัติโดยทั่วไปคุณควรเก็บbreakข้อความไว้ในสวิตช์ ในกรณีที่คุณไม่ต้องการreturnงบในอนาคตก็จะช่วยลดโอกาสที่จะตกลงไปในcaseอนาคต


แก้ไขโพสต์เพื่อแสดงให้เห็นว่าเหตุใดโซลูชันนี้จึงทำงานได้ไม่ดี
houbysoft

2

สำหรับ "ความถูกต้อง" การเข้าครั้งเดียวบล็อกทางออกเดียวเป็นความคิดที่ดี อย่างน้อยพวกเขาก็เป็นตอนที่ฉันเรียนปริญญาวิทยาศาสตร์คอมพิวเตอร์ ดังนั้นฉันอาจจะประกาศตัวแปรกำหนดให้ในสวิตช์และกลับมาอีกครั้งเมื่อสิ้นสุดฟังก์ชัน


2

คุณคิดอย่างไร? ลบออกได้ไหม หรือคุณจะเก็บไว้เพื่อเพิ่ม "ความถูกต้อง"?

สามารถลบออกได้ ใช้return เป็นว่าสถานการณ์ที่ breakไม่ควรใช้


1

น่าสนใจ. ฉันทามติจากคำตอบเหล่านี้ส่วนใหญ่ดูเหมือนว่าbreakคำสั่งที่ซ้ำซ้อนเป็นสิ่งที่ไม่จำเป็น ในทางกลับกันฉันอ่านbreakคำสั่งในสวิตช์เป็น 'ปิด' ของเคส caseบล็อกที่ไม่จบลงด้วยbreakแนวโน้มที่จะกระโดดออกมาที่ฉันเนื่องจากอาจมีข้อผิดพลาด

ฉันรู้ว่านั่นไม่ใช่วิธีที่เมื่อมี a returnแทนbreakแต่นั่นเป็นวิธีที่ตาของฉัน 'อ่าน' เคสบล็อกในสวิตช์ดังนั้นโดยส่วนตัวแล้วฉันอยากให้แต่ละcaseคู่จับคู่กับไฟล์break. แต่คอมไพเลอร์จำนวนมากไม่บ่นเกี่ยวกับbreakหลังจากที่returnฟุ่มเฟือย / ไม่สามารถเข้าถึงได้และดูเหมือนว่าฉันจะอยู่ในคนส่วนน้อยอยู่ดี

ดังนั้นกำจัดต่อไปbreakreturn

หมายเหตุ: ทั้งหมดนี้ไม่สนใจว่าการละเมิดกฎการเข้า / ออกครั้งเดียวเป็นความคิดที่ดีหรือไม่ เท่าที่ผ่านมาฉันมีความเห็นว่าน่าเสียดายที่เปลี่ยนแปลงไปตามสถานการณ์ ...


0

ฉันบอกว่าให้ลบออก หากรหัสของคุณไม่สามารถอ่านได้จนคุณต้องหยุดพักไว้ตรงนั้น 'เพื่ออยู่ในด้านที่ปลอดภัย' คุณควรพิจารณารูปแบบการเข้ารหัสของคุณใหม่ :)

นอกจากนี้ฉันมักไม่ชอบที่จะไม่ผสมตัวแบ่งและผลตอบแทนในคำสั่งสวิตช์ แต่ให้ยึดติดกับหนึ่งในนั้น


0

ฉันเองมักจะแพ้breaks สาเหตุหนึ่งของนิสัยนี้อาจมาจากขั้นตอนการเขียนโปรแกรมหน้าต่างสำหรับแอพ Windows:

โดยส่วนตัวแล้วฉันพบว่าวิธีนี้ง่ายกว่ารวบรัดและยืดหยุ่นกว่าการประกาศตัวแปรผลตอบแทนที่กำหนดโดยตัวจัดการแต่ละตัวจากนั้นส่งคืนในตอนท้าย ด้วยวิธีการนี้breaks มีความซ้ำซ้อนดังนั้นจึงควรไป - พวกเขาไม่ใช้จุดประสงค์ที่เป็นประโยชน์ (ทางวากยสัมพันธ์หรือ IMO ทางสายตา) และขยายโค้ดเท่านั้น


0

ฉันคิดว่าตัวแบ่ง * มีไว้เพื่อจุดประสงค์ มันคือการรักษา 'อุดมการณ์' ของการเขียนโปรแกรมให้คงอยู่ หากเราเพียงแค่ 'ตั้งโปรแกรม' โค้ดของเราโดยไม่มีการเชื่อมโยงเชิงตรรกะบางทีคุณอาจอ่านได้ในตอนนี้ แต่ลองพรุ่งนี้ ลองอธิบายให้หัวหน้าของคุณฟัง ลองรันบน Windows 3030

Bleah แนวคิดนั้นง่ายมาก:


/ * แค่คำถามเล็กน้อย คุณดื่มกาแฟมากแค่ไหนในขณะที่อ่านข้างต้น ไอทีทำให้ระบบพังในบางครั้ง * /


0

ออกจากรหัสที่จุดเดียว ที่ช่วยให้อ่านโค้ดได้ดีขึ้น การเพิ่มคำสั่งส่งคืน (การออกหลายรายการ) ระหว่างกันจะทำให้การดีบักทำได้ยาก


0

หากคุณมีรหัสประเภท "การค้นหา" คุณสามารถจัดแพคเกจประโยคกรณีสวิตช์ด้วยวิธีการด้วยตัวเอง

ฉันมีสิ่งเหล่านี้อยู่ในระบบ "งานอดิเรก" ที่ฉันกำลังพัฒนาเพื่อความสนุกสนาน:

(ใช่นั่นคือพื้นที่ GURPS ... )

ฉันเห็นด้วยกับคนอื่น ๆ ว่าในกรณีส่วนใหญ่คุณควรหลีกเลี่ยงการส่งคืนมากกว่าหนึ่งวิธีและฉันตระหนักดีว่าอันนี้อาจได้รับการปรับใช้เป็นอาร์เรย์หรืออย่างอื่นได้ดีกว่า ฉันเพิ่งพบว่า switch-case-return เป็นการจับคู่ตารางการค้นหาที่ค่อนข้างง่ายโดยมีความสัมพันธ์ 1-1 ระหว่างอินพุตและเอาต์พุตเช่นเดียวกับสิ่งข้างต้น (เกมเล่นตามบทบาทเต็มไปด้วยพวกเขาฉันแน่ใจว่ามีอยู่ในเกมอื่น ๆ "ธุรกิจ" ด้วย): D

ในทางกลับกันถ้า case-clause มีความซับซ้อนมากขึ้นหรือมีบางอย่างเกิดขึ้นหลังจาก switch-statement ฉันไม่แนะนำให้ใช้ return แต่จะตั้งค่าตัวแปรในสวิตช์ปิดท้ายด้วยการหยุดพักและส่งคืน ค่าของตัวแปรในตอนท้าย

(ใน ... มือที่สาม ... คุณสามารถ refactor สวิทช์เป็นวิธีการของมันเองได้เสมอ ... ฉันสงสัยว่ามันจะมีผลต่อประสิทธิภาพและมันจะไม่แปลกใจเลยถ้าคอมไพเลอร์สมัยใหม่สามารถจำได้ว่าเป็น สิ่งที่สามารถแทรกเข้ามา ... )

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