`การแตก 'และ` การปฏิบัติการ' ที่แย่ ๆ


191

เจ้านายของฉันพูดถึงอย่างเมินเฉยว่าโปรแกรมเมอร์ที่ไม่ดีใช้breakและcontinueวนซ้ำ

ฉันใช้มันตลอดเวลาเพราะมันสมเหตุสมผล ให้ฉันแสดงแรงบันดาลใจ:

function verify(object) {
    if (object->value < 0) return false;
    if (object->value > object->max_value) return false;
    if (object->name == "") return false;
    ...
}

จุดที่นี่คือก่อนอื่นฟังก์ชันตรวจสอบว่าเงื่อนไขถูกต้องจากนั้นดำเนินการฟังก์ชันการทำงานจริง IMO เช่นเดียวกับลูป:

while (primary_condition) {
    if (loop_count > 1000) break;
    if (time_exect > 3600) break;
    if (this->data == "undefined") continue;
    if (this->skip == true) continue;
    ...
}

ฉันคิดว่าสิ่งนี้ทำให้การอ่านและแก้ปัญหาง่ายขึ้น แต่ฉันก็ไม่เห็นข้อเสียเช่นกัน


2
ใช้เวลาไม่นานนักที่จะลืมสิ่งที่ทำ

57
ไม่ใช่ทั้งคู่ก็คือ การรู้ว่าจะใช้เมื่อใดเป็นกุญแจสำคัญ พวกเขาเป็นเครื่องมือในกล่องเครื่องมือ คุณใช้พวกเขาเมื่อพวกเขาให้รหัสที่ชัดเจนและรวบรัด
orj

67
ฉันไม่สามารถสนับสนุนการเข้ารหัสรูปแบบนี้ได้อย่างแข็งแรงพอ หลายระดับของเงื่อนไขที่ซ้อนกันแย่กว่าวิธีนี้มาก ฉันมักจะไม่กล้าทำเรื่องสไตล์การเขียนโค้ด แต่มันก็เกือบจะเป็นข้อตกลงสำหรับฉัน
Emil H

9
เห็นได้ชัดว่าเจ้านายของคุณเขียนโค้ดไม่เพียงพอ หากเขาทำเขาจะรู้ว่าคำหลักทั้งหมด (ใช่แล้วgoto) มีประโยชน์ในบางกรณี
sakisk

57
โปรแกรมเมอร์ที่ไม่ดีใช้ตัวแบ่งและดำเนินการต่อไม่ได้หมายความว่าโปรแกรมเมอร์ที่ดีทำไม่ได้ โปรแกรมเมอร์ที่ไม่ดีใช้ถ้าและในขณะที่เช่นกัน
mouviciel

คำตอบ:


240

เมื่อใช้ที่จุดเริ่มต้นของบล็อกตามการตรวจสอบครั้งแรกพวกเขาทำหน้าที่เป็นเงื่อนไขเบื้องต้นดังนั้นจึงเป็นเรื่องที่ดี

เมื่อใช้ในช่วงกลางของบล็อกโดยมีรหัสอยู่รอบ ๆ พวกมันทำตัวเหมือนกับดักที่ซ่อนอยู่ดังนั้นมันจึงไม่ดี


6
@ คำพูด: มันอาจจะเป็นที่ถกเถียงกันอยู่ว่ารูทีนใด ๆ ที่มีจุดทางออกหลายจุดเป็นรูทีนที่แยกตัวประกอบไม่ดี รูทีนแฟคตอริ่งที่เหมาะสมควรทำสิ่งหนึ่งและสิ่งหนึ่งเท่านั้น
bit-twiddler

79
@ bit-twiddler: นี่เป็นความคิด C-ish มาก ตัวแปรชั่วคราวสามารถแก้ไขได้ในภายหลังดังนั้นหนึ่งบรรทัดที่พิมพ์ได้ 20 บรรทัดสามารถลบผลลัพธ์ที่สร้างขึ้นอย่างระมัดระวัง ผลตอบแทนทันที (หรือทำลายหรือยังคง) แต่เป็นที่ชัดเจนมาก: ฉันสามารถหยุดอ่านตอนนี้เพราะผมรู้ว่ามันไม่อาจได้รับการแก้ไขต่อไปลง มันดีสำหรับสมองตัวน้อยของฉันทำให้การตัดผ่านโค้ดง่ายขึ้น
Matthieu M.

15
@ Matthieu ฉันเห็นด้วย ออกจากบล็อกเมื่อคุณได้รับผลลัพธ์ที่ตรงตามวัตถุประสงค์ของบล็อก
Evan Plaice

8
@ bit-twiddler - หลักการ single-exit-point แยกออกจาก single-responsibility-Principle ฉันไม่เห็นด้วยที่การตรวจสอบจะแยกจากการทำหน้าที่เป็นความรับผิดชอบเดียวของ WRT เสมอ ในความเป็นจริง "ความรับผิดชอบเดี่ยว" มักจะทำให้ฉันเป็นศัพท์เฉพาะทาง ตัวอย่างเช่นในการแก้สมการกำลังสองควรคำนวณการแบ่งแยกเป็นความรับผิดชอบที่แยกจากกันหรือไม่? หรือสูตรสมการกำลังสองทั้งหมดสามารถเป็นความรับผิดชอบเดียวได้หรือไม่? ฉันขอยืนยันว่ามันขึ้นอยู่กับว่าคุณมีการใช้งานแยกต่างหากสำหรับการเลือกปฏิบัติ - มิฉะนั้นการปฏิบัติตามความรับผิดชอบแยกต่างหากอาจมากเกินไป
Steve314

10
คำตอบนั้นเป็นกฎง่ายๆไม่ใช่กฎที่ยาก มันทำงานได้ในกรณีส่วนใหญ่อย่าลังเลที่จะทำลายมันถ้ามันสมเหตุสมผลในบริบทของคุณ
Klaim

87

คุณสามารถอ่านการเขียนโปรแกรมแบบมีโครงสร้างของ Donald Knuth ในปี 1974 โดยใช้คำสั่ง goซึ่งเขากล่าวถึงการใช้งานต่าง ๆ ของสิ่งgo toที่เป็นที่ต้องการในเชิงโครงสร้าง พวกเขารวมถึงเทียบเท่าbreakและcontinueงบ (การใช้งานจำนวนมากgo toในนั้นได้รับการพัฒนาเป็นโครงสร้างที่ จำกัด มากขึ้น) เจ้านายของคุณเป็นคนประเภทที่เรียก Knuth ว่าเป็นโปรแกรมเมอร์ที่ไม่ดีหรือไม่?

(ตัวอย่างที่ให้ความสนใจฉันโดยทั่วไปแล้วbreakและcontinueไม่ชอบโดยคนที่ชอบหนึ่งรายการและหนึ่งทางออกจากชิ้นส่วนของรหัสใด ๆ และคนประเภทนั้นก็ขมวดคิ้วในหลายreturnงบ)


8
คนส่วนใหญ่ที่ชอบฟังก์ชั่นและขั้นตอนการมีจุดเข้าและออกเพียงครั้งเดียวโตขึ้นจาก Pascal ปาสคาลไม่ใช่ภาษาแรกที่ฉันได้เรียนรู้ แต่มันมีผลกระทบอย่างลึกซึ้งต่อวิธีการจัดโครงสร้างรหัสของฉันจนถึงทุกวันนี้ ผู้คนให้ความเห็นเกี่ยวกับความง่ายในการอ่านรหัส Java ของฉัน นั่นเป็นเพราะฉันหลีกเลี่ยงจุดออกหลายจุดรวมถึงการประกาศ intermixing ด้วยรหัส ฉันพยายามอย่างดีที่สุดที่จะประกาศตัวแปรท้องถิ่นทุกตัวที่ใช้ในวิธีที่ด้านบนของวิธีการ การปฏิบัตินี้หลีกเลี่ยงการใช้รหัสโดยการบังคับให้ฉันเก็บวิธีการสั้น ๆ
bit-twiddler

5
ปาสกาลยังมีฟังก์ชั่นที่ซ้อนกัน เพียงแค่พูดใน '...
Shog9

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

28
@ bit-twiddler: ฉันไม่แน่ใจเกี่ยวกับเรื่องนั้น ฉันยังคงใช้ปาสคาลในวันนี้และโดยทั่วไปฉันคิดว่า "ทางออกเดียวรายการเดียว" หรืออย่างน้อยก็เป็นส่วนทางออกเดียวของมันในฐานะการเขียนโปรแกรมลัทธิขนส่งสินค้า ฉันเพียงแค่พิจารณาBreak, ContinueและExitเป็นเครื่องมือในกล่องเครื่องมือของฉัน; ฉันใช้พวกเขาในที่ที่ทำให้โค้ดติดตามได้ง่ายขึ้นและไม่ใช้พวกเขาในที่ที่จะทำให้อ่านยากขึ้น
Mason Wheeler

2
@ bit-twiddler: แก้ไขให้ดี ฉันจะเพิ่มด้วยเมื่อคุณลงไปยังบล็อกที่พอดีกับหน้าจอได้อย่างง่ายดายจุดทางออกหลายจุดจะกลายเป็นปัญหาน้อยกว่ามาก
Shog9

44

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

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

หากการทำงานของคุณจะสั้นมากถ้าคุณมีวงเดียวหรือที่เลวร้ายที่สุดสองวงซ้อนกันและถ้าร่างกายวงสั้นมากแล้วมันเป็นที่ชัดเจนมากสิ่งที่breakหรือcontinueไม่ นอกจากนี้ยังเป็นที่ชัดเจนว่ามีหลายreturnงบที่ทำ

ปัญหาเหล่านี้ได้รับการแก้ไขใน "รหัสสะอาด" โดย Robert C. Martin และใน "Refactoring" โดย Martin Fowler


12
"ทำให้ฟังก์ชั่นของคุณเล็กลงแล้วทำให้มันเล็กลง" -Robert C. Martin ฉันพบว่ามันใช้งานได้ดีอย่างน่าประหลาดใจ ทุกครั้งที่คุณเห็นบล็อกของรหัสในฟังก์ชั่นที่ต้องการความคิดเห็นอธิบายสิ่งที่มันทำห่อมันลงในฟังก์ชั่นแยกต่างหากที่มีชื่ออธิบาย แม้ว่าจะเป็นเพียงไม่กี่บรรทัดและแม้ว่าจะใช้เพียงครั้งเดียว การปฏิบัตินี้ช่วยลดปัญหาส่วนใหญ่ที่มีการหยุดพัก / ดำเนินการต่อหรือส่งคืนหลายครั้ง
Dima

2
@Mikail: ความซับซ้อนของวงจรโดยทั่วไปมีความสัมพันธ์อย่างมากกับ SLOC ซึ่งหมายความว่าคำแนะนำสามารถทำให้ง่ายขึ้นเพื่อ "ไม่ได้เขียนฟังก์ชั่นที่ยาวนาน"
John R. Strohm

3
แนวคิดของจุดทางออกเดียวถูกตีความผิดอย่างกว้างขวาง กาลครั้งหนึ่งฟังก์ชั่นไม่จำเป็นต้องส่งคืนผู้โทร พวกเขาสามารถกลับไปที่จุดอื่น นี่เป็นเรื่องปกติในภาษาแอสเซมบลี Fortran มีโครงสร้างพิเศษสำหรับสิ่งนี้ คุณสามารถส่งผ่านหมายเลขคำสั่งที่นำหน้าด้วยเครื่องหมายแอมเปอร์แซนด์CALL P(X, Y, &10)และในกรณีที่เกิดข้อผิดพลาดฟังก์ชันสามารถส่งการควบคุมไปยังคำสั่งนั้นแทนที่จะกลับไปยังจุดที่โทร
วินไคลน์

@kevincline เท่าที่เห็นกับ Lua เป็นต้น
Qix

1
@cjsimon คุณได้รับมัน ฟังก์ชั่นไม่ควรมีขนาดเล็ก ชั้นเรียนควรมีขนาดเล็กเกินไป
Dima

39

โปรแกรมเมอร์ที่ไม่ดีสามารถพูดได้อย่างสมบูรณ์ (เช่นเดียวกับ Sith) โปรแกรมเมอร์ที่ดีใช้วิธีการแก้ปัญหาที่ชัดเจนที่สุด ( ทุกสิ่งอื่น ๆ เหมือนกัน )

การใช้ตัวแบ่งและดำเนินการต่อทำให้รหัสยากที่จะปฏิบัติตาม แต่ถ้าการแทนที่พวกมันทำให้โค้ดยากขึ้นกว่าเดิมนั่นเป็นการเปลี่ยนแปลงที่แย่มาก

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


ใช่ฉันพูดเกินจริงถึงจำนวนเงื่อนไขเพื่อเป็นตัวอย่างของคดีที่จะออก
มิคาอิล

9
ตัวอย่างของรหัสทดแทนที่คุณแนะนำคืออะไร ฉันคิดว่ามันเป็นตัวอย่างที่เหมาะสมของคำแถลงการณ์ยาม
simgineer

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

@nocomprende ฉันไม่แน่ใจว่าคุณกำลังทำอะไรอยู่ "เป็นไปได้" ที่นี่ไม่ได้บ่งบอกว่าไม่มีทางออกที่ดีที่สุด - สมบูรณ์แบบเท่านั้น แต่ความคมชัดสูงสุดไม่ใช่สิ่ง มันเป็นเรื่องส่วนตัวหลังจากทั้งหมด
Matthew อ่าน

22

คนส่วนใหญ่คิดว่าเป็นความคิดที่ไม่ดีเพราะพฤติกรรมไม่สามารถคาดเดาได้ง่าย หากคุณอ่านรหัสและเห็นwhile(x < 1000){}ว่าคุณคิดว่ามันจะทำงานจนกว่า x> = 1,000 ... แต่ถ้ามีตัวแบ่งอยู่ตรงกลางนั่นก็ไม่ถือว่าเป็นจริงดังนั้นคุณจึงไม่ไว้ใจ วนลูป ...

มันเป็นเหตุผลเดียวกันกับที่คนไม่ชอบ GOTO: แน่นอนว่ามันสามารถใช้งานได้ดี แต่ก็สามารถนำไปสู่รหัสสปาเก็ตตี้ godawful ซึ่งรหัสจะกระโดดแบบสุ่มจากส่วนหนึ่งไปยังอีกส่วนหนึ่ง

สำหรับตัวฉันเองถ้าฉันจะวนซ้ำที่มีเงื่อนไขมากกว่าหนึ่งข้อฉันจะwhile(x){}สลับ X เป็นเท็จเมื่อฉันต้องการแยกออก ผลลัพธ์สุดท้ายจะเหมือนกันและทุกคนที่อ่านโค้ดจะรู้ว่าควรมองสิ่งต่าง ๆ ที่เปลี่ยนค่าของ X ให้มากขึ้น


2
+1 พูดได้ดีมากและ +1 (ถ้าฉันทำได้อีกwhile(notDone){ }วิธี)
FrustratedWithFormsDesigner

5
มิคาอิล: ปัญหาของการหยุดพักคือเงื่อนไขสุดท้ายของการวนซ้ำนั้นไม่เคยถูกกล่าวถึงในที่เดียว ทำให้ยากต่อการคาดการณ์สภาพหลังลูป ในกรณีเล็กน้อยนี้ (> = 1,000) มันไม่ยาก เพิ่มคำสั่ง if จำนวนมากและระดับการซ้อนที่แตกต่างกันมันอาจกลายเป็นเรื่องยากมากในการกำหนดโพสต์เงื่อนไขของลูป
S.Lott

S.Lott กระแทกเล็บอย่างเต็มที่บนหัว นิพจน์ที่ควบคุมการวนซ้ำควรรวมทุกเงื่อนไขที่ต้องทำตามเพื่อดำเนินการทำซ้ำ
bit-twiddler

6
การแทนที่break;ด้วยx=false;ไม่ทำให้รหัสของคุณชัดเจนยิ่งขึ้น คุณยังต้องค้นหาเนื้อความสำหรับคำสั่งนั้น และในกรณีที่x=false;คุณจะต้องตรวจสอบว่ามันไม่x=true;ลงไปอีก
Sjoerd

14
เมื่อมีคนพูดว่า "ฉันเห็น x และฉันถือว่า y แต่ถ้าคุณทำ z ข้อสันนิษฐานนั้นไม่ถือ" ฉันมักจะคิดว่า "ดังนั้นอย่าทำสมมติฐานโง่ ๆ " หลายคนจะทำให้มันง่ายขึ้น "เมื่อฉันเห็นwhile (x < 1000)ฉันคิดว่ามันจะทำงาน 1,000 ครั้ง" มีเหตุผลหลายประการที่ทำให้มันผิดแม้ว่าxจะเป็นศูนย์ในตอนแรก ตัวอย่างเช่นใครบอกว่าxจะเพิ่มขึ้นอย่างแม่นยำหนึ่งครั้งในระหว่างลูปและไม่เคยแก้ไขด้วยวิธีอื่นใด? แม้สำหรับการสันนิษฐานของคุณเองเพียงเพราะชุดบางอย่างx >= 1000ไม่ได้หมายความว่าการวนซ้ำจะสิ้นสุด - อาจถูกตั้งค่ากลับเป็นช่วงก่อนที่จะตรวจสอบสภาพ
Steve314

14

ใช่คุณสามารถ [เขียน] โปรแกรมโดยไม่มีคำสั่ง break (หรือส่งคืนจากตรงกลางของลูปซึ่งทำสิ่งเดียวกัน) แต่คุณอาจต้องแนะนำตัวแปรเพิ่มเติมและ / หรือการทำสำเนาโค้ดซึ่งโดยทั่วไปจะทำให้โปรแกรมเข้าใจยากขึ้น Pascal (ภาษาการเขียนโปรแกรม) นั้นแย่มากโดยเฉพาะอย่างยิ่งสำหรับโปรแกรมเมอร์มือใหม่ด้วยเหตุผลนั้น หัวหน้าของคุณต้องการให้คุณเขียนโปรแกรมในโครงสร้างการควบคุมของ Pascal หาก Linus Torvalds อยู่ในรองเท้าของคุณเขาอาจแสดงนิ้วกลางของเจ้านายคุณ!

มีผลลัพธ์ทางวิทยาศาสตร์คอมพิวเตอร์ที่เรียกว่าลำดับชั้นของโครงสร้างการควบคุมของ Kosaraju ซึ่งมีอายุย้อนไปถึงปี 1973 และมีการกล่าวถึงในบทความที่มีชื่อเสียง (เพิ่มเติม) ของ Knuth ใน gotos จากปี 1974 (เอกสารฉบับนี้ Knuth ได้รับการแนะนำข้างต้นแล้วโดย David Thornley .) สิ่งที่สเราโคสาราจูพิสูจน์แล้วในปี 1973 ก็คือว่ามันเป็นไปไม่ได้ที่จะเขียนโปรแกรมทั้งหมดที่มีการแบ่งหลายระดับความลึกของnลงในโปรแกรมที่มีความลึกแบ่งน้อยกว่าnโดยไม่ต้องแนะนำตัวแปรเสริม แต่สมมุติว่านั่นเป็นเพียงผลลัพธ์ทางทฤษฎีเท่านั้น (เพียงเพิ่มตัวแปรพิเศษสองสามอย่าง! แน่นอนคุณสามารถทำเช่นนั้นเพื่อเอาใจเจ้านายของคุณ ... )

สิ่งที่สำคัญกว่าจากมุมมองด้านวิศวกรรมซอฟต์แวร์คือกระดาษ 1995 ล่าสุดโดย Eric S. Roberts บรรดาศักดิ์Loop Exits และ Programming แบบมีโครงสร้าง: เปิดการอภิปรายอีกครั้ง ( http://cs.stanford.edu/people/eroberts/papers/SIGCSE-) 1995 / LoopExits.pdf ) โรเบิร์ตส์สรุปการศึกษาเชิงประจักษ์หลายครั้งโดยคนอื่นก่อนเขา ตัวอย่างเช่นเมื่อกลุ่มนักเรียนประเภท CS101 ถูกขอให้เขียนรหัสสำหรับฟังก์ชั่นที่ใช้การค้นหาตามลำดับในอาเรย์ผู้เขียนของการศึกษากล่าวว่าต่อไปนี้เกี่ยวกับนักเรียนที่ใช้ตัวแบ่ง / return / goto เพื่อออกจาก วนลูปการค้นหาตามลำดับเมื่อพบองค์ประกอบ:

ฉันยังไม่พบคนเดียวที่พยายามใช้โปรแกรมโดยใช้ [ลักษณะนี้] ที่สร้างโซลูชันที่ไม่ถูกต้อง

โรเบิร์ตก็บอกว่า:

นักเรียนที่พยายามแก้ปัญหาโดยไม่ใช้ผลตอบแทนที่ชัดเจนจาก for for fared ก็ดีน้อยกว่ามาก: มีนักเรียนเพียงเจ็ดจาก 42 คนที่พยายามใช้กลยุทธ์นี้เพื่อจัดการกับวิธีแก้ไขที่ถูกต้อง ตัวเลขดังกล่าวแสดงถึงอัตราความสำเร็จน้อยกว่า 20%

ใช่คุณอาจมีประสบการณ์มากกว่านักเรียน CS101 แต่โดยไม่ต้องใช้คำสั่ง break (หรือส่งคืน / goto จากลูปตรงกลาง) ในที่สุดคุณจะเขียนโค้ดที่ในขณะที่โครงสร้างที่มีชื่ออยู่นั้นมีขนดกเพียงพอในแง่ของตรรกะเพิ่มเติม ตัวแปรและการทำสำเนารหัสที่บางคนอาจเป็นตัวคุณเองจะใส่บั๊กแบบตรรกะในขณะที่พยายามติดตามสไตล์การเข้ารหัสของเจ้านายของคุณ

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


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

9

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


:) ใช่ตัวอย่างที่ฉันให้ไว้เป็นแนวคิด
มิคาอิล

7

ตัวอย่างที่คุณให้ไม่จำเป็นต้องหยุดพักหรือดำเนินต่อไป:

while (primary-condition AND
       loop-count <= 1000 AND
       time-exec <= 3600) {
   when (data != "undefined" AND
           NOT skip)
      do-something-useful;
   }

'ปัญหา' ของฉันที่มี 4 บรรทัดในตัวอย่างของคุณคือพวกเขาทั้งหมดอยู่ในระดับเดียวกัน แต่พวกเขาทำสิ่งที่แตกต่าง: บางตัวแบ่งบางส่วนดำเนินการต่อ ... คุณต้องอ่านแต่ละบรรทัด

ในแนวทางที่ซ้อนกันของฉันยิ่งคุณเข้าไปมากเท่าไหร่รหัสก็จะยิ่งมีประโยชน์มากขึ้นเท่านั้น

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


+1 แต่จริงๆแล้ว<การเปรียบเทียบของคุณจะต้อง<=ตรงกับโซลูชัน
OPs

3
ในกรณีส่วนใหญ่หากมีความลึกที่ต้องการใช้ break / return เพื่อจัดการโฟลว์คอนโทรลฟังก์ชัน / เมธอดของบุคคลนั้นซับซ้อนเกินไป
bit-twiddler

6

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

หากใช้ตัวแบ่งจะไม่ทำให้โค้ดอ่านง่ายขึ้นสั้นลงเพื่อเรียกใช้หรือบันทึกรอบในการประมวลผลในลักษณะที่สำคัญดังนั้นจึงเป็นการดีที่สุดที่จะไม่ใช้มัน ฉันมักจะเขียนโค้ดให้กับ "ตัวหารร่วมที่ต่ำที่สุด" เมื่อเป็นไปได้เพื่อให้แน่ใจว่าใครก็ตามที่ติดตามฉันสามารถดูรหัสของฉันและเข้าใจว่าเกิดอะไรขึ้น (ฉันไม่ประสบความสำเร็จในเรื่องนี้เสมอ) การแบ่งลดนั้นเพราะพวกเขาแนะนำจุดเข้า / ออกแปลก ๆ ในทางที่ผิดพวกเขาสามารถทำงานได้มากเหมือนคำสั่ง "goto"


ฉันเห็นด้วยกับคะแนนทั้งสอง! ถึงจุดที่สองของคุณ - ฉันคิดว่ามันง่ายกว่าที่จะติดตามโพสต์ต้นฉบับของฉันเพราะมันอ่านได้เหมือนภาษาอังกฤษ หากคุณมีการรวมกันของเงื่อนไขใน 1 ถ้าคำสั่งแล้วมันเกือบถอดรหัสที่จะคิดออกว่าจะเกิดอะไรขึ้นถ้าหากจะดำเนินการจริง
Mikhail

@Mikail: ตัวอย่างที่คุณให้มามีความเห็นแก่ประโยชน์เล็กน้อยสำหรับสัจนิยมเฉพาะ อย่างที่ฉันเห็นมันตัวอย่างเหล่านั้นชัดเจนกระชับง่ายต่อการอ่าน ลูปส่วนใหญ่ไม่เป็นเช่นนั้น ลูปส่วนใหญ่มีเหตุผลอื่น ๆ ที่พวกเขากำลังดำเนินการอยู่และมีเงื่อนไขที่ซับซ้อนกว่า ในกรณีเหล่านี้ที่การหยุดพัก / ดำเนินการต่ออาจไม่เป็นการใช้งานที่ดีที่สุดเพราะจะทำให้ตรรกะสับสนเมื่ออ่าน
Joel Etherton

4

ไม่อย่างแน่นอน ... ใช่การใช้งานgotoไม่ดีเพราะมันทำให้โครงสร้างของโปรแกรมของคุณแย่ลงและมันก็เป็นเรื่องยากมากที่จะเข้าใจโฟลว์การควบคุม

แต่การใช้คำสั่งเช่นbreakและcontinueจำเป็นอย่างยิ่งในทุกวันนี้และไม่ถือว่าเป็นการฝึกเขียนโปรแกรมที่ไม่ดีเลย

และยังไม่ยากที่จะทำความเข้าใจในการควบคุมการไหลในการใช้งานและbreak continueในโครงสร้างเช่นคำสั่งเป็นอย่างที่จำเป็นswitchbreak


2
ฉันไม่ได้ใช้ "ดำเนินการต่อ" ตั้งแต่ฉันเรียนรู้ C ครั้งแรกในปี 1981 มันเป็นคุณสมบัติภาษาที่ไม่จำเป็นเนื่องจากรหัสที่ถูกข้ามโดยคำสั่งดำเนินการต่อสามารถถูกห่อหุ้มด้วยคำสั่งควบคุมตามเงื่อนไข
bit-twiddler

12
ฉันต้องการใช้การดำเนินการต่อในกรณีเหล่านี้เนื่องจากทำให้แน่ใจว่ารหัสของฉันไม่ได้กลายเป็นรหัสลูกศร ฉันเกลียดรหัสลูกศรมากกว่าคำสั่งประเภท goto ฉันอ่านมันด้วยเช่นกันว่า "ถ้าข้อความนี้เป็นจริงให้ข้ามส่วนที่เหลือของลูปนี้และทำต่อไปในรอบถัดไป" มีประโยชน์มากเมื่ออยู่ที่จุดเริ่มต้นของลูป (มีประโยชน์น้อยกว่าในขณะลูป)
jsternberg

@jsternberg สำหรับผู้ชนะ! :-)
Notinlist

3

ความคิดที่สำคัญนั้นมาจากความสามารถในการวิเคราะห์โปรแกรมของคุณ หากคุณมีรายการเดียวและมีทางออกเดียวคณิตศาสตร์ที่จำเป็นในการแสดงสถานะที่เป็นไปได้นั้นง่ายกว่าถ้าคุณต้องจัดการเส้นทางฟอร์กกิ้ง

บางส่วนความยากลำบากนี้สะท้อนให้เห็นถึงความสามารถในการคิดเหตุผลเกี่ยวกับรหัสของคุณ

ตรงไปตรงมารหัสที่สองของคุณไม่ชัดเจน มันทำอะไรอยู่? ทำต่อไป 'ทำต่อ' หรือทำต่อไป? ฉันไม่รู้. อย่างน้อยตัวอย่างแรกของคุณชัดเจน


เมื่อฉันทำงานในโครงการที่ผู้จัดการบังคับให้ใช้ฉันต้องใช้ผังงานเพื่อจดจำการใช้งานและเส้นทางออกหลายทางทำให้รหัส th สับสนมากขึ้น ...
umlcat

ความคิดเห็น "ตรงไปตรง" ของคุณคือวากยสัมพันธ์ - "ถัดไป" เป็นสิ่งที่ perl; ภาษาปกติใช้ "ดำเนินการต่อ" เพื่อหมายถึง "ข้ามลูปนี้"
มิคาอิล

@ Mik อาจจะ "ข้ามการทำซ้ำนี้" จะเป็นคำอธิบายที่ดีกว่า ขอแสดงความนับถือ Dr. IM Pedantic
Pete Wilson

@ Mikail: แน่นอน แต่เมื่อภาษาใดภาษาหนึ่งทำงานได้หลายภาษาอาจทำให้เกิดข้อผิดพลาดเมื่อไวยากรณ์ไม่ได้อยู่ระหว่างภาษา
พอลนาธาน

แต่คณิตศาสตร์ไม่ใช่การเขียนโปรแกรม รหัสแสดงออกได้มากกว่าคณิตศาสตร์ ฉันได้รับรายการเดียว / ทางออกเดียวอาจทำให้ผังงานดูดีขึ้น แต่มีค่าใช้จ่ายเท่าไร (เช่นที่ที่ตัวแบ่ง / ส่งคืนสามารถทำให้โค้ดทำงานได้ดีขึ้น)
Evan Plaice

3

ฉันจะแทนที่ข้อมูลโค้ดที่สองของคุณด้วย

while (primary_condition && (loop_count <= 1000 && time_exect <= 3600)) {
    if (this->data != "undefined" && this->skip != true) {
        ..
    }
}

ไม่ได้ด้วยเหตุผลใด ๆ ของความตึงเครียด - จริง ๆ แล้วฉันคิดว่านี่เป็นเรื่องง่ายที่จะอ่านและสำหรับใครบางคนที่จะเข้าใจสิ่งที่เกิดขึ้น โดยทั่วไปแล้วการพูดถึงเงื่อนไขสำหรับลูปของคุณควรอยู่ในสภาพที่ไม่ได้ทิ้งให้เกลื่อนทั่วร่างกาย อย่างไรก็ตามมีบางสถานการณ์ที่breakและcontinueสามารถช่วยให้การอ่าน breakmoreso มากกว่าที่continueฉันอาจเพิ่ม: D


ในขณะที่ฉันไม่เห็นด้วย "จริง ๆ แล้วฉันคิดว่านี่เป็นเรื่องง่ายที่จะอ่าน" นี้จะบรรลุวัตถุประสงค์เดียวกันกับรหัสข้างต้น ฉันไม่เคยคิดเลยว่า 'หยุด' ในฐานะผู้ประกอบการลัดวงจรมาจนถึงตอนนี้ แต่มันก็สมเหตุสมผลดี สำหรับ "โดยทั่วไปการพูดเงื่อนไขสำหรับลูปของคุณควรจะอยู่ภายใต้เงื่อนไขของลูปนั้น" คุณจะทำอย่างไรเมื่อคุณกำลังประมวลผลลูป foreach เนื่องจากไม่มีวิธีแทรกตรรกะเชิงเงื่อนไขในนิยามลูป
Evan Plaice

@Evan ไม่สามารถใช้เงื่อนไขกับforeachลูปได้เนื่องจากจะวนซ้ำทุกไอเท็มในคอลเลกชัน การforวนซ้ำคล้ายกันซึ่งไม่ควรมีจุดสิ้นสุดแบบมีเงื่อนไข หากคุณต้องการจุดสิ้นสุดแบบมีเงื่อนไขคุณต้องใช้การwhileวนซ้ำ
El Ronnoco

1
@Evan ฉันเห็นจุดของคุณแล้ว - นั่นคือ 'ถ้าคุณต้องการแยกวง foreach ออกมา?' - breakเอาล่ะฉันควรจะมีความคิดเห็นสูงสุดจากลูป
El Ronnoco

2

ฉันไม่เห็นด้วยกับเจ้านายของคุณ มีสถานที่ที่เหมาะสมสำหรับการอยู่breakและcontinueที่จะใช้ ในความเป็นจริงเหตุผลที่ execeptions structured techniquesและการจัดการข้อยกเว้นได้รับการแนะนำให้รู้จักกับการเขียนโปรแกรมภาษาที่ทันสมัยคือการที่คุณไม่สามารถแก้ปัญหาโดยใช้เพียงทุก

ในบันทึกด้านข้าง ฉันไม่ต้องการเริ่มการสนทนาทางศาสนาที่นี่ แต่คุณสามารถปรับโครงสร้างรหัสของคุณให้อ่านง่ายขึ้นเช่นนี้:

while (primary_condition) {
    if (loop_count > 1000) || (time_exect > 3600) {
        break;
    } else if ( ( this->data != "undefined") && ( !this->skip ) ) {
       ... // where the real work of the loop happens
    }
}

เมื่อทราบอีกด้านหนึ่ง

ฉันเองไม่ชอบการใช้( flag == true )เงื่อนไขเพราะถ้าตัวแปรเป็นบูลีนอยู่แล้วคุณจะแนะนำการเปรียบเทียบเพิ่มเติมที่ต้องเกิดขึ้นเมื่อค่าบูลีนมีคำตอบที่คุณต้องการ - แน่นอนว่าคุณมั่นใจได้ว่าคอมไพเลอร์ของคุณจะ เพิ่มประสิทธิภาพที่เปรียบเทียบพิเศษ


ฉันถามคำถามนี้มาหลายปีแล้ว วิธีของคุณ ('ถ้า (ตั้งค่าสถานะ) {... }') นั้นมีความกระชับมากกว่าและอาจดูเป็น 'มืออาชีพ' หรือ 'ผู้เชี่ยวชาญ' มากกว่า แต่รู้แล้วมันมักจะหมายความว่าผู้อ่าน / ผู้ดูแลจะต้องขัดจังหวะตัวเองสั้น ๆ เพื่อจำสิ่งที่สร้างหมายถึง; และเพื่อให้แน่ใจในความรู้สึกของการทดสอบ ขณะนี้ฉันกำลังใช้ 'if (flag == จริง) {... }' เพียงเพราะดูเหมือนว่าจะเป็นเอกสารที่ดีกว่า เดือนหน้า? Quien sabe?
Pete Wilson

2
@Pete - คำที่ไม่สั้นแต่สง่างาม คุณสามารถวาฟเฟิลทุกอย่างที่คุณต้องการ แต่ถ้าคุณเป็นห่วงว่าผู้อ่าน / ผู้ดูแลไม่เข้าใจสิ่งที่booleanเป็นหรือสิ่งที่หมายถึงคำศัพท์สั้น / สง่างามแล้วคุณอาจจ้างบำรุงรักษาอย่างชาญฉลาด ;-)
Zeke Hansell

@Peat ฉันยังยืนอยู่ข้างข้อความของฉันเกี่ยวกับรหัสที่สร้างขึ้น คุณกำลังทำการเปรียบเทียบอีกหนึ่งรายการโดยเปรียบเทียบแฟล็กกับค่าคงที่ก่อนที่จะประเมินค่าบูลีนของนิพจน์ ทำไมต้องทำให้ยากกว่าที่เคยเป็นมาตัวแปรแฟล็กมีค่าที่คุณต้องการแล้ว!
Zeke Hansell

+1 ได้ดี แน่นอนว่าสวยงามกว่าตัวอย่างในอดีตมาก
Evan Plaice

2

ฉันเห็นด้วยกับเจ้านายของคุณ พวกเขาไม่ดีเพราะพวกเขาผลิตวิธีที่มีความซับซ้อนสูง cyclomatic วิธีการดังกล่าวนั้นยากต่อการอ่านและทดสอบได้ยาก โชคดีที่มีทางออกที่ง่าย แยกเนื้อหาของลูปเป็นวิธีแยกต่างหากโดยที่ "ทำต่อ" จะกลายเป็น "ส่งคืน" "คืน" ดีกว่าเพราะหลังจาก "คืน" จบแล้ว - ไม่ต้องกังวลกับสภาพท้องถิ่น

สำหรับ "break" แยกลูปออกเป็นวิธีแยกต่างหากโดยแทนที่ "break" ด้วย "return"

หากวิธีการแยกต้องการอาร์กิวเมนต์จำนวนมากนั่นเป็นข้อบ่งชี้ในการแยกคลาส - รวบรวมไว้ในวัตถุบริบท


0

ฉันคิดว่ามันเป็นปัญหาเมื่อซ้อนกันลึกเข้าไปในหลายลูป เป็นการยากที่จะทราบว่าคุณกำลังทำลายวงไหน มันอาจจะยากที่จะติดตามต่อไปเช่นกัน แต่ฉันคิดว่าความเจ็บปวดที่แท้จริงมาจากการแตก - ตรรกะอาจยากที่จะติดตาม


2
ที่จริงแล้วมันง่ายที่จะดูว่าคุณเยื้องอย่างถูกต้องมีความหมายของคำสั่งเหล่านั้นภายในและไม่ง่วงเกินไป

@delnan - นั่นเป็นข้อสันนิษฐานมากมาย)
davidhaskins

2
ใช่โดยเฉพาะอย่างยิ่งคนสุดท้าย
Michael K

ดี # 1 เป็นสิ่งจำเป็นสำหรับการเขียนโปรแกรมอย่างจริงจังต่อไป # 2 เป็นที่คาดหวังจากทุกคนที่เรียกว่าโปรแกรมเมอร์และ # 3 ค่อนข้างมีประโยชน์โดยทั่วไป;)

บางภาษา (สนับสนุนเฉพาะสคริปต์ที่ฉันรู้) สนับสนุนbreak 2; สำหรับคนอื่น ๆ ผมคิดว่าธงบูลชั่วคราวจะถูกนำมาใช้
มิคาอิล

0

ตราบใดที่มันไม่ได้ถูกใช้เป็น goto ที่ปลอมตัวเหมือนในตัวอย่างต่อไปนี้:

do
{
      if (foo)
      {
             /*** code ***/
             break;
      }

      if (bar)
      {
             /*** code ***/
             break;
      }
} while (0);

ฉันสบายดีกับพวกเขา (ตัวอย่างที่เห็นในรหัสการผลิต meh)


คุณจะแนะนำให้ใช้กรณีเช่นนี้เพื่อสร้างฟังก์ชั่นหรือไม่?
Mikhail

ใช่และถ้าเป็นไปไม่ได้ก็ข้ามไปธรรมดา เมื่อฉันเห็นสิ่งที่ต้องทำฉันคิดว่าการทำซ้ำไม่ใช่บริบทที่จะจำลองการกระโดด
SuperBloup

โอ้ฉันเห็นด้วยฉันแค่ถามว่าคุณจะทำอย่างไร :) นักวิทยาศาสตร์คอมพิวเตอร์ทำมันซ้ำ ๆ
มิคาอิล

0

ฉันไม่ชอบสไตล์เหล่านี้ นี่คือสิ่งที่ฉันต้องการ:

function verify(object)
{
    if not (object->value < 0) 
       and not(object->value > object->max_value)
       and not(object->name == "") 
       {
         do somethign important
       }
    else return false; //probably not necessary since this function doesn't even seem to be defined to return anything...?
}

ฉันไม่ชอบที่returnจะยกเลิกฟังก์ชั่น returnมันรู้สึกเหมือนการละเมิดของ

การใช้งานbreakยังไม่ชัดเจนในการอ่าน

ยังดีกว่า:

notdone := primarycondition    
while (notDone)
{
    if (loop_count > 1000) or (time_exect > 3600)
    {
       notDone := false; 
    }
    else
    { 
        skipCurrentIteration := (this->data == "undefined") or (this->skip == true) 

        if not skipCurrentIteration
        {
           do something
        } 
        ...
    }
}

การซ้อนที่น้อยลงและเงื่อนไขที่ซับซ้อนได้รับการเปลี่ยนเป็นตัวแปร (ในโปรแกรมจริงที่คุณต้องมีชื่อที่ดีกว่าชัด ... )

(รหัสทั้งหมดข้างต้นเป็นรหัสหลอก)


11
คุณอยากได้รัง 3 ระดับมากกว่าสิ่งที่ฉันพิมพ์ด้านบนหรือไม่
Mikhail

@ Mikail: ใช่หรือฉันจะกำหนดผลลัพธ์ของเงื่อนไขให้กับตัวแปร ฉันคิดว่ามันง่ายมากที่จะเข้าใจกว่าตรรกะของและbreak continueความผิดปกติในการวนซ้ำทำให้รู้สึกแปลก ๆ และฉันไม่ชอบมัน
FrustratedWithFormsDesigner

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

@Mikail: อ่า ฉันไม่ได้ใช้บ่อยและเมื่อฉันอ่านมันฉันสับสนกับความหมาย อีกเหตุผลที่ฉันไม่ชอบ : P ให้ฉันสักครู่เพื่ออัปเดต ...
FrustratedWithFormsDesigner

7
การวางซ้อนมากเกินไปจะทำลายความสามารถในการอ่าน และบางครั้งการหลีกเลี่ยงการหยุดพัก / ดำเนินการต่อแนะนำความจำเป็นของการคว่ำตรรกะของคุณในการทดสอบตามเงื่อนไขของคุณซึ่งสามารถนำไปสู่การตีความที่ผิดในสิ่งที่โค้ดของคุณกำลังทำอยู่ - ฉันแค่พูดในนั้น
Zeke Hansell

0

ไม่มันเป็นวิธีในการแก้ปัญหาและมีวิธีอื่นในการแก้ปัญหา

ภาษากระแสหลักจำนวนมากในปัจจุบัน (Java, .NET (C # + VB), PHP, เขียนของคุณเอง) ใช้ "break" และ "Continue" เพื่อข้ามลูป พวกเขาทั้งสองประโยค "โครงสร้าง goto"

ปราศจากพวกเขา:

String myKey = "mars";

int i = 0; bool found = false;
while ((i < MyList.Count) && (not found)) {
  found = (MyList[i].key == myKey);
  i++;   
}
if (found)
  ShowMessage("Key is " + i.toString());
else
  ShowMessage("Not found.");

กับพวกเขาเหล่านั้น:

String myKey = "mars";

for (i = 0; i < MyList.Count; i++) {
  if (MyList[i].key == myKey)
    break;
}
ShowMessage("Key is " + i.toString());

โปรดทราบว่ารหัส "ตัวแบ่ง" และ "ต่อ" จะสั้นกว่าและมักจะเปลี่ยนเป็น "ในขณะที่" ประโยคเป็น "สำหรับ" หรือ "foreach" ประโยค

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

ที่จริงฉันทำงานในบางโครงการซึ่งเป็นข้อบังคับในการใช้ประโยคเหล่านั้น

นักพัฒนาบางคนอาจคิดว่าพวกเขาไม่ใช่คนไร้สาระ แต่สมมุติว่าถ้าเราต้องลบพวกเขาเราต้องลบ "ในขณะที่" และ "ทำในขณะที่" ("ทำซ้ำจนถึง" คุณปาสกาลพวก) ด้วย ;-)

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


ขออภัยที่จะจู้จี้จุกจิก แต่ตัวอย่างที่สองของคุณจะหายไปเมื่อไม่พบผลลัพธ์ที่สำคัญ (ดังนั้นแน่นอนว่ามันดูสั้นกว่ามาก)
FrustratedWithFormsDesigner

2
ไม่ต้องพูดถึงว่าตัวอย่างแรกใช้งานได้เฉพาะถ้าคีย์เป็นคีย์สุดท้ายในรายการ
มิคาอิล

@FrustratedWithFormsDesigner อย่างแน่นอน ฉันใส่ purpouse เพื่อแสดงว่าทำไมจึงเป็นวิธีที่ดีกว่า ;-)
umlcat

อย่างไรก็ตามคุณมีสองกิจวัตรที่มีความหมายต่างกัน ดังนั้นจึงไม่เทียบเท่าในเชิงตรรกะ
bit-twiddler

2
ตัวอย่างที่สองของคุณมีบั๊กสองตัวหนึ่งประโยค 1. มันจะไม่รวบรวมเพราะตัววนซ้ำไม่ได้ถูกประกาศนอกขอบเขตของ for loop (ดังนั้นจึงไม่สามารถใช้ได้ในเอาต์พุตสตริง) 2. แม้ว่าจะมีการประกาศตัววนซ้ำนอกลูปหากไม่พบคีย์ในคอลเลกชันเอาต์พุตสตริงจะพิมพ์คีย์ของไอเท็มสุดท้ายในรายการ
Evan Plaice

0

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

ฉันใช้ C # เป็นตัวอย่างที่นี่พิจารณากรณีของการต้องการย้ำผ่านคอลเลกชัน แต่เราต้องการเพียงองค์ประกอบที่ตอบสนองเพรดิเคตบางส่วนและเราไม่ต้องการทำซ้ำมากกว่า 100 ครั้งสูงสุด

for (var i = 0; i < collection.Count; i++)
{
    if (!Predicate(item)) continue;
    if (i >= 100) break; // at first I used a > here which is a bug. another good thing about the more declarative style!

    DoStuff(item);
}

นี่ดูสะอาดหมดจด มันไม่ยากที่จะเข้าใจ ฉันคิดว่ามันคงเป็นไปได้ที่จะได้รับประโยชน์มากมาย เปรียบเทียบกับสิ่งต่อไปนี้:

foreach (var item in collection.Where(Predicate).Take(100))
    DoStuff(item);

อาจจะไม่ได้อยู่ในวิธีนี้ บางทีการกรองนี้ควรทำก่อนที่การรวบรวมจะถูกส่งผ่านไปยังวิธีนี้ อย่างไรก็ตามโดยการย้ายออกจากสิ่งที่อยู่ในระดับต่ำและมุ่งเน้นไปที่ตรรกะทางธุรกิจจริง ๆ มันจะชัดเจนยิ่งขึ้นในสิ่งที่เราสนใจจริง ๆ มันกลายเป็นเรื่องง่ายกว่าที่จะแยกรหัสของเราออกเป็นโมดูลที่ยึดติดกับแนวทางการออกแบบที่ดี บน.

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


-1

Code Completeมีส่วนที่ดีเกี่ยวกับการใช้gotoและผลตอบแทนหลายรายการจากรูทีนหรือลูป

โดยทั่วไปแล้วการปฏิบัติไม่ใช่เรื่องเลวร้าย breakหรือcontinueบอกสิ่งที่เกิดขึ้นต่อไป และฉันเห็นด้วยกับสิ่งนี้

Steve McConnell (ผู้เขียน Code Complete) ใช้ตัวอย่างเกือบเหมือนกันกับคุณเพื่อแสดงข้อดีของการใช้gotoคำสั่งต่างๆ

อย่างไรก็ตามการใช้งานมากเกินไปbreakหรือcontinueอาจนำไปสู่ซอฟต์แวร์ที่ซับซ้อนและไม่สามารถแก้ไขได้

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