'ทำ ... ในขณะที่' กับ 'ในขณะที่'


86

รายการที่ซ้ำกันที่เป็นไปได้:
While กับ Do While
เมื่อใดฉันควรใช้ do-while แทน while ลูป

ฉันเขียนโปรแกรมมาระยะหนึ่งแล้ว (ทำงาน 2 ปี + ปริญญา 4.5 ปี + เตรียมอุดมศึกษา 1 ปี) และฉันไม่เคยใช้ลูป do-while ที่ไม่ถูกบังคับให้เรียนในหลักสูตร Introduction to Programming ฉันมีความรู้สึกมากขึ้นเรื่อย ๆ ว่าฉันเขียนโปรแกรมผิดถ้าฉันไม่เคยเจออะไรที่เป็นพื้นฐาน

เป็นไปได้ไหมที่ฉันไม่ได้เผชิญกับสถานการณ์ที่ถูกต้อง?

มีตัวอย่างอะไรบ้างที่จำเป็นต้องใช้ do-while แทน a while

(การเรียนของฉันเกือบทั้งหมดเป็นภาษา C / C ++ และงานของฉันอยู่ในภาษา C # ดังนั้นหากมีภาษาอื่นที่เหมาะสมอย่างยิ่งเพราะ do-whiles ทำงานแตกต่างกันคำถามเหล่านี้ก็ใช้ไม่ได้จริงๆ)

เพื่อชี้แจง ... ฉันรู้ความแตกต่างระหว่าง a whileและdo-while. ในขณะที่ตรวจสอบเงื่อนไขการออกจากนั้นดำเนินการ do-whileดำเนินการแล้วตรวจสอบเงื่อนไขการออก


43
สำหรับสิ่งที่คุ้มค่าหลังจากสิบปีของการเขียนโปรแกรมในอาชีพของฉันฉันใช้ลูป do-while เช่นหนึ่งหรือสองครั้ง
Matt Greer

@ แมท - นั่นทำให้ฉันรู้สึกดีขึ้น อย่างน้อยก็หมายความว่าฉันไม่ได้อยู่คนเดียว
mphair

2
ฉันจะแมตต์ที่สองและเพิ่มอีกประมาณทศวรรษ ฉันแทบไม่เคยใช้ลูป do-while เลย
quentin-star ใน

ซ้ำกันหลายรายการ นี่คือสิ่งที่เชื่อมโยงไปยังกลุ่มของพวกเขา: stackoverflow.com/questions/3094972/…
gnovice

3
“ คำถามหลัก” ที่ถูกต้องน่าจะเป็นstackoverflow.com/questions/224059/…
Donal Fellows

คำตอบ:


116

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

do
{
   try to access resource...
   put up message box with retry option

} while (user says retry);

3
ดังนั้นฉันเดาว่าสิ่งนี้จะตามมาภายใต้ "ฉันไม่ได้เจอสถานการณ์แบบนั้น"
mphair

7
บอกตามตรงว่าฉันแทบจะไม่เจอสถานการณ์เมื่อต้องใช้ do .. ในขณะที่ ..
Stan R.

1
อาจจะสั้นหน่อย แต่บ๊อบเป๊ะ ทำ / ขณะที่ควรจะใช้เมื่อคุณต้องการที่จะเรียกใช้รหัสบล็อกอย่างน้อยหนึ่งครั้ง คุณควรใช้ while loop เมื่อคุณไม่รู้ว่าคุณต้องการเรียกใช้ครั้งเดียวหรือไม่ ที่กล่าวว่าฉันสามารถบอกคุณได้ว่าด้วยประสบการณ์การพัฒนาประมาณ 15 ปีฉันใช้ในขณะที่วนซ้ำมากกว่า do / while หลายเท่า
ConsultUtah

1
ฉันเคยใช้เป็นครั้งคราวเช่นกันแม้ว่าจะไม่ค่อยบ่อยนัก หลังจากนั้นไม่นานพวกเขามักจะได้รับการปรับโครงสร้างใหม่เป็นแบบ while loop เช่นกัน - เพียงเพราะพื้นที่รอบ ๆ มันเปลี่ยนไปและทำ ...
Joshua

2
เป็นเรื่องธรรมดาพอสมควร แต่ฉันไม่เห็นว่าทำไมในตัวอย่างของคุณคุณไม่ใช้ while loop และฉันไม่เห็นว่าทำไมคำตอบนี้ถึงได้รับการโหวต

65

do-while จะดีกว่าถ้าคอมไพเลอร์ไม่มีความสามารถในการปรับให้เหมาะสม do-while มีการกระโดดแบบมีเงื่อนไขเพียงครั้งเดียวซึ่งต่างจากการกระโดดแบบมีเงื่อนไขและการกระโดดแบบไม่มีเงื่อนไข สำหรับซีพียูที่มีการวางท่อและไม่ทำการทำนายแบบสาขาสิ่งนี้สามารถสร้างความแตกต่างอย่างมากในประสิทธิภาพของลูปแบบแน่น

นอกจากนี้เนื่องจากคอมไพเลอร์ส่วนใหญ่ฉลาดพอที่จะทำการเพิ่มประสิทธิภาพนี้ลูปทั้งหมดที่พบในโค้ดที่ถอดรหัสแล้วมักจะเป็น do-while (หากตัวถอดรหัสยังรบกวนการสร้างลูปใหม่จาก gotos ในเครื่องย้อนหลังเลย)


5
+1 สำหรับการเพิ่มข้อมูลทางเทคนิคที่เกี่ยวข้องให้กับตัวเลือกระหว่างรูปแบบการวนซ้ำ
quentin-star ใน

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

3
@ เจเรมี: การกระโดดที่คุณพูดถึงอยู่นอกวงมันไม่ได้ดำเนินการ N ครั้ง
Ben Voigt

1
ลองพิจารณาการใช้ do-while แบบคลาสสิกในอุปกรณ์ของ Duff (โดยที่ while loop จะถูกเปลี่ยนเป็น do-while ที่ไม่มีการควบคุมด้วยขั้นตอนที่ใหญ่กว่าบวกกับตารางการกระโดดเพื่อจัดการกับส่วนที่เหลือ) ซึ่งจะช่วยลดค่าใช้จ่ายของลูปได้อย่างมากในแอปพลิเคชันเช่น memset, memcmp, memcpy มันอาจเพิ่มปริมาณงานได้ 10
Ben Voigt

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

12

ฉันใช้สิ่งนี้ในฟังก์ชัน TryDeleteDirectory มันเป็นแบบนี้

do
{
    try
    {
        DisableReadOnly(directory);
        directory.Delete(true);
    }
    catch (Exception)
    {
        retryDeleteDirectoryCount++;
    }
} while (Directory.Exists(fullPath) && retryDeleteDirectoryCount < 4);

ดี. นี่เป็นตัวอย่างแรกที่สมเหตุสมผลที่จะห่อด้วย do ... while
Joshua

4
ทำไม / ถึงดีกว่ามาตรฐานwhileอย่างไร?
Josh Stodola

ลูปจะดำเนินการครั้งเดียวเสมอดังนั้นคุณอาจต้องการทำบางอย่างจากนั้นลองอีกครั้งหากล้มเหลว หากคุณใช้ while ลูปปกติคุณจะตรวจสอบว่าล้มเหลวหรือไม่ก่อนที่คุณจะทำซ้ำในครั้งแรก
NibblyPig

1
@SLC แต่คุณไม่ต้องการตรวจสอบว่ามีไดเร็กทอรีอยู่ก่อนหรือไม่?
Josh Stodola

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

11

Do while มีประโยชน์เมื่อคุณต้องการดำเนินการบางอย่างอย่างน้อยหนึ่งครั้ง สำหรับตัวอย่างที่ดีในการใช้ do while กับ while สมมติว่าคุณต้องการทำสิ่งต่อไปนี้: เครื่องคิดเลข

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

do
{
    //do calculator logic here
    //prompt user for continue here
} while(cont==true);//cont is short for continue

2
ที่จริงแล้วตอนนี้ที่คุณพูดถึงอินเทอร์เฟซที่ขับเคลื่อนด้วยเมนูบนคอนโซลทุกประเภทจะทำได้ดีใน do ... ในขณะที่วนซ้ำเช่นกัน ตัวอย่างเช่นการแจ้งสำหรับตัวเลือก (ทีละปุ่ม) และออกเฉพาะเมื่อพวกเขาเลือกดำเนินการต่อหรือออก
Joshua

7
continueเป็นคีย์เวิร์ด D
Thomas Eding

Atrinithis: ฮ่า ๆ ... ฉันลื่นขึ้น ขอบคุณที่แก้ไขฉันที่นั่น

== trueไม่จำเป็น cont == trueถ้า cont เป็นจริงส่งคืนจริง นั่นไร้ประโยชน์โดยสิ้นเชิง
Mr.DeleteMyMessages

11

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

อย่างที่ใคร ๆ พูดกันคุณใช้do ... whileลูปเมื่อคุณต้องการเรียกใช้ร่างกายอย่างน้อยหนึ่งครั้ง แต่คุณต้องการทำเช่นนั้นภายใต้สถานการณ์ใด?

ดีชั้นที่ชัดเจนที่สุดของสถานการณ์ที่ฉันสามารถคิดจะเมื่อเริ่มต้นค่า ( "unprimed") สภาพการตรวจสอบเป็นเช่นเดียวกับเมื่อคุณต้องการที่จะออกจาก ซึ่งหมายความว่าคุณจำเป็นต้องเรียกใช้งาน loop body หนึ่งครั้งเพื่อกำหนดเงื่อนไขให้เป็นค่าที่ไม่ได้ออกจากนั้นจึงทำการทำซ้ำตามเงื่อนไขนั้น เกิดอะไรขึ้นกับโปรแกรมเมอร์ที่ขี้เกียจมากมีคนตัดสินใจที่จะรวมสิ่งนี้ไว้ในโครงสร้างการควบคุม

ตัวอย่างเช่นการอ่านอักขระจากพอร์ตอนุกรมที่มีการหมดเวลาอาจอยู่ในรูปแบบ (ใน Python):

response_buffer = []
char_read = port.read(1)

while char_read:
    response_buffer.append(char_read)
    char_read = port.read(1)

# When there's nothing to read after 1s, there is no more data

response = ''.join(response_buffer)

หมายเหตุการทำซ้ำรหัส: char_read = port.read(1) . ถ้า Python มีdo ... whileลูปฉันอาจใช้:

do:
    char_read = port.read(1)
    response_buffer.append(char_read)
while char_read

ประโยชน์เพิ่มเติมสำหรับภาษาที่สร้างขอบเขตใหม่สำหรับลูป: char_readไม่ทำให้เนมสเปซของฟังก์ชันก่อมลพิษ แต่โปรดทราบด้วยว่ามีวิธีที่ดีกว่าในการทำเช่นนี้และนั่นคือการใช้Noneค่าของ Python :

response_buffer = []
char_read = None

while char_read != '':
    char_read = port.read(1)
    response_buffer.append(char_read)

response = ''.join(response_buffer)

ดังนั้นนี่คือประเด็นสำคัญของฉัน: ในภาษาที่มีประเภทที่เป็นโมฆะสถานการณ์จะinitial_value == exit_valueเกิดขึ้นน้อยกว่ามากและนั่นอาจเป็นสาเหตุที่คุณไม่พบเจอ ฉันไม่ได้บอกว่ามันไม่เคยเกิดขึ้นเพราะยังมีบางครั้งที่ฟังก์ชันจะกลับมาNoneแสดงถึงเงื่อนไขที่ถูกต้อง แต่ในความเห็นที่รีบร้อนและพิจารณาสั้น ๆ สิ่งนี้จะเกิดขึ้นอีกมากหากภาษาที่คุณใช้ไม่อนุญาตให้มีค่าที่บ่งบอกว่าตัวแปรนี้ยังไม่ได้เริ่มต้น

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


นี่เป็นหนึ่งในคำตอบที่น่าสนใจที่ฉันได้อ่านที่นี่ ผลงานที่ดี
Bob Moore

ทั้งสองเวอร์ชันไม่เทียบเท่ากัน หากผลตอบแทนครั้งแรกอ่านNoneที่whileรุ่นอย่างถูกต้องไม่ได้เพิ่มอะไรให้บัฟเฟอร์การตอบสนอง แต่คุณdoรุ่นมักจะเพิ่มบางสิ่งบางอย่าง
David Stone

@DavidStone read()ไม่ควรกลับมาNoneอีก หากคุณกำลังใช้ไลบรารีอยู่สถานที่ตั้งจะใช้ไม่ได้ (กล่าวคือค่า Sentinel ไม่ได้อยู่ในชุดของค่าตรวจสอบที่เป็นไปได้)
ย้อนกลับ

ที่มีการแก้ไขล่าสุดของคุณผมเห็นสิ่งที่ฉันควรจะพูดเป็นแทน'' Noneค่าบางประเภทที่ประเมินเป็นเท็จ ชอล์กขึ้นตามความไม่คุ้นเคยกับreadฟังก์ชันของ Python
David Stone

@DavidStone ฉันไม่เข้าใจ หากread()ส่งคืน''จะไม่มีสิ่งใดต่อท้ายสตริงมันว่างเปล่า
59

7

ฉันใช้มันอย่างยุติธรรมเมื่อฉันอยู่ในโรงเรียน แต่ไม่มากนักตั้งแต่นั้นมา

ตามทฤษฎีแล้วจะมีประโยชน์เมื่อคุณต้องการให้ loop body ดำเนินการหนึ่งครั้งก่อนการตรวจสอบเงื่อนไขการออก ปัญหาคือสำหรับบางกรณีที่ฉันไม่ต้องการตรวจสอบก่อนโดยทั่วไปฉันต้องการให้การตรวจสอบออกตรงกลางของวงวนมากกว่าที่ส่วนท้ายสุด ในกรณีนี้ฉันชอบที่จะใช้ที่รู้จักกันดีfor (;;)กับif (condition) exit;ที่ไหนสักแห่งในร่างกาย

ในความเป็นจริงถ้าฉันรู้สึกสั่นคลอนเล็กน้อยกับเงื่อนไขการออกจากลูปบางครั้งฉันพบว่ามันมีประโยชน์ที่จะเริ่มเขียนลูปเป็นfor (;;) {}คำสั่งออกเมื่อจำเป็นจากนั้นเมื่อฉันทำเสร็จแล้วฉันจะเห็นว่ามันสามารถ " ทำความสะอาด "โดยการย้ายการเริ่มต้นเงื่อนไขการออกและ / หรือรหัสส่วนเพิ่มภายในforวงเล็บของ


5
จากความอยากรู้อยากเห็น ... ทำไม "for (;;)" แทนที่จะเป็น "while (true)"?
mphair

4
น่าจะเป็นแค่รสชาติ ฉันโตขึ้นเพื่อให้สมfor(;;)กับ "ลูปไม่มีที่สิ้นสุด" ในขณะที่while(true)ฉันต้องหยุดและคิดถึง อาจเป็นเพราะฉันเขียนโค้ด C ก่อนที่จะมีไฟล์true. ย้อนกลับไปในวันที่เราเป็นเพียงTRUEมาโครและหากมีสิ่งผิดปกติเกิดขึ้นฉันจะต้องโน้มน้าวตัวเองว่ามาโครไม่ได้ถูกกำหนดใหม่ให้เป็น0อย่างนั้น โดยที่for(;;)ไม่มีโอกาสนั้น ถ้าคุณยืนยันในแบบฟอร์ม while ฉันเกือบจะเห็นwhile (1)แล้ว แน่นอนว่าบางคนอาจสงสัยว่ามันไม่ใช่ตัวอักษร l ...
TED

1
@mphair: ใช่ถ้าคุณจดข้อความที่ตัวแก้ไขใส่ไว้เมื่อคุณเป็นตัวเอียงหรือcodeifyข้อความคุณสามารถพิมพ์ลงในช่องความคิดเห็นได้โดยตรง ฉันเคยเห็นคนบางคนใส่ไฮเปอร์ลิงก์ แต่มันก็ยากเกินไปสำหรับฉัน
TED

2
@TED: สัญกรณ์ที่ฉันต้องการสำหรับการวนซ้ำจนกว่าจะชัดเจน - ออกคือ "do {} while (1);" อนึ่งในระบบฝังตัวทำงานกระบวนทัศน์ลูปปกติของฉันคือ "i = 10; do {} while (- i);" สำหรับลูปที่แน่นจะเร็วกว่าปกติมากสำหรับ (); ฉันคิดว่ามันสามารถอ่านได้มากกว่าที่จะใช้รูปแบบการวนซ้ำเมื่อไม่จำเป็นต้องมีการเพิ่มขึ้นมากกว่าที่จะใช้สำหรับ () โดยพลการในกรณีที่ไม่สำคัญต่อประสิทธิภาพ
supercat

2
การเพิ่มความคลาดเคลื่อน while (1) และสำหรับ (;;) ฉันเคยเห็นรหัสที่ใช้สำหรับ (EVER) ด้วย EVER ที่กำหนดให้เป็น ;;
asr

6

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

rc = get_something();
while (rc == wrong_stuff)
{
    rc = get_something();
}

do
{
    rc = get_something();
}
while (rc == wrong_stuff);

6

do whileคือถ้าคุณต้องการเรียกใช้บล็อกโค้ดอย่างน้อยหนึ่งครั้ง whileในทางกลับกันจะไม่ทำงานเสมอไปขึ้นอยู่กับเกณฑ์ที่ระบุ


5

มันง่ายอย่างที่:

เงื่อนไขเบื้องต้นเทียบกับสภาวะหลังสภาวะ

  • ในขณะที่ (cond) {... } - เงื่อนไขเบื้องต้นจะรันโค้ดหลังจากการตรวจสอบเท่านั้น
  • do {... } while (cond) - postcondition โค้ดจะถูกเรียกใช้งานอย่างน้อยหนึ่งครั้ง

ตอนนี้คุณรู้ความลับแล้ว.. ใช้อย่างชาญฉลาด :)


1
อย่างที่ฉันพูดฉันรู้ว่าพวกเขาทำงานอย่างไรฉันไม่แน่ใจว่ากรณีใดที่เหมาะสมกว่าอีกกรณีหนึ่ง
mphair

เป็นเหตุผลที่คุณใช้ do {} ในขณะที่คุณรู้แน่ว่าคุณต้องผ่านลูปอย่างน้อยหนึ่งครั้ง เช่นถ้าคุณมีฟังก์ชันที่ค้นหาองค์ประกอบในอาร์เรย์และก่อนหน้านี้คุณได้ใส่ if array.IsEmpty () แล้วกลับ; . หากผ่านการตรวจสอบนั้นคุณสามารถใช้ do {} while ได้อย่างปลอดภัย do-while ก็ง่ายที่จะคิดว่าเป็นวนซ้ำ: "ฉันกินจนกว่าฉันจะพอใจ" แปลว่าทำ {กิน ();} ในขณะที่ (! พอใจ ();) การทดสอบเงื่อนไขก่อนการวนซ้ำถือว่าปลอดภัยกว่า .. และนั่นเป็นสาเหตุที่ใช้บ่อยขึ้น
Ioan Paul Pirau

4

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

do
{
   ...
} while (0)

มักใช้สำหรับ #defines แบบหลายบรรทัด ตัวอย่างเช่น:

#define compute_values     \
   area = pi * r * r;      \
   volume = area * h

สิ่งนี้ใช้ได้ดีสำหรับ:

r = 4;
h = 3;
compute_values;

- แต่ - มี gotcha สำหรับ:

if (shape == circle)  compute_values;

เมื่อสิ่งนี้ขยายเป็น:

if (shape == circle) area = pi *r * r;
volume = area * h;

หากคุณรวมเข้าใน do ... ในขณะที่ (0) วนซ้ำมันจะขยายเป็นบล็อกเดียว

if (shape == circle)
  do
  {
    area = pi * r * r;
    volume = area * h;
  } while (0);

2

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

ด้วย do-while คุณจะได้รับอินพุตในขณะที่อินพุตไม่ถูกต้อง ด้วย while-loop ปกติคุณจะได้รับอินพุตหนึ่งครั้ง แต่ถ้ามันไม่ถูกต้องคุณจะได้รับมันซ้ำแล้วซ้ำอีกจนกว่าจะถูกต้อง ไม่ยากที่จะเห็นว่าอดีตนั้นสั้นกว่าสง่างามกว่าและดูแลรักษาง่ายกว่าถ้าร่างกายของห่วงมีความซับซ้อนมากขึ้น


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

@mphair: จริงๆแล้วสำหรับสถานการณ์แบบนั้นบางครั้งฉันอาจจะชอบใช้ "do {} while (0);" มากกว่า วนซ้ำโดยใช้ "ต่อ;" หากอินพุตของผู้ใช้ไม่สามารถยอมรับได้ หากมีปัญหาและข้อความเพียงรายการเดียวให้ใช้ "do {} while (1);" และ "ทำลาย;" ใช้งานได้ดี แต่หากมีเหตุผลหลายประการที่ต้องการให้กลับเข้ามาใหม่ให้เลือก "ดำเนินการต่อ" สร้างผลงานออกมาได้สวยงามมากขึ้น
supercat


1

ฉันเคยใช้ a do whileเมื่อฉันอ่านค่า Sentinel ที่จุดเริ่มต้นของไฟล์ แต่นอกเหนือจากนั้นฉันไม่คิดว่ามันผิดปกติที่โครงสร้างนี้ไม่ได้ถูกใช้บ่อยเกินไป - do-whiles เป็นสถานการณ์จริงๆ

-- file --
5
Joe
Bob
Jake
Sarah
Sue

-- code --
int MAX;
int count = 0;
do {
MAX = a.readLine();
k[count] = a.readLine();
count++;
} while(count <= MAX)

1

นี่คือทฤษฎีของฉันว่าทำไมคนส่วนใหญ่ (รวมถึงฉัน) ชอบ while () {} ลูปที่จะทำ {} while (): A while () {} ลูปสามารถปรับให้ทำเหมือน do.. while () วนซ้ำ มันไม่จริง. การวนรอบขณะอยู่ในลักษณะที่ "กว้างกว่า" โปรแกรมเมอร์ก็ชอบที่จะเข้าใจรูปแบบได้ง่าย ในขณะที่ลูปบอกทันทีว่าค่าคงที่คืออะไรและนี่เป็นสิ่งที่ดี

นี่คือความหมายของสิ่งที่ "ทั่วไปกว่า" ทำสิ่งนี้.. ในขณะที่วนซ้ำ:

do {
 A;
 if (condition) INV=false; 
 B;
} while(INV);

การแปลงเป็น while loop นั้นตรงไปตรงมา:

INV=true;
while(INV) {
 A;
 if (condition) INV=false; 
 B;
}

ตอนนี้เราใช้แบบจำลองในขณะที่วนซ้ำ:

while(INV) {
     A;
     if (condition) INV=false; 
     B;
}

และแปลงสิ่งนี้เป็น do .. ในขณะที่วนซ้ำให้ผลมหึมานี้:

if (INV) {
 do
 {
         A;
         if (condition) INV=false; 
         B;

 } while(INV)
}

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


1
แทนที่ "do {} while (x);" วนเข้าไปใน "while (x);" loop กำหนดให้ X เป็นเงื่อนไขที่สามารถ "ลงสีพื้น" ได้อย่างง่ายดายหรือเป็นจริง "ตามธรรมชาติ" ในรอบแรก สำหรับฉันคำสั่ง priming ก่อนลูปบ่งบอกว่าบางสิ่งบางอย่างในลูปนั้นต้องการการรองพื้นและลูป while (x) {}; "หมายความว่าลูปอาจทำงานเป็นศูนย์ครั้งหากฉันต้องการลูปที่จะดำเนินการอย่างน้อยหนึ่งครั้งฉัน ใช้ลูป "do {} while (x);"
supercat

1

ฉันกำลังเขียนโปรแกรมประมาณ 12 ปีและเพียง 3 เดือนที่ผ่านมาฉันได้พบกับสถานการณ์ที่สะดวกมากที่จะใช้ do-while เนื่องจากการทำซ้ำครั้งเดียวเป็นสิ่งที่จำเป็นเสมอก่อนที่จะตรวจสอบเงื่อนไข ดังนั้นเดาครั้งใหญ่ของคุณอยู่ข้างหน้า :)


1
เกือบทุกครั้งที่ฉันเคยเห็นสิ่งที่ต้องทำ ... ในขณะที่มันเป็นเพราะความไม่เข้าใจในปัญหาและเกี่ยวข้องกับการแฮ็กที่น่ากลัว มีข้อยกเว้น แต่โดยทั่วไปถ้าคุณมีสิ่งที่ต้องทำ ... ในขณะที่คุณควรคิดใหม่ว่าคุณกำลังทำอะไรอยู่ ... :-)
Brian Knoblauch

2
หากคุณอยู่ตรงไหนแล้ว do-while จะถูกแยกออกจากภาษาโปรแกรมทั้งหมดเพื่อไม่ให้โปรแกรมเมอร์สับสน :)
Narek

@Narek: เกือบเจ็ดปีแล้วที่คุณเขียนสิ่งนี้คุณมีสถานการณ์มากกว่านี้หรือไม่ที่do whileจะเป็นทางออกที่ดีกว่าโดยไม่ต้องเสียใจ?
chqrlie

ใช่อาจจะอีกครั้ง: D
Narek

1

ฉันนึกภาพไม่ออกว่าคุณจะหายไปนานขนาดนี้ได้อย่างไรโดยไม่ต้องใช้do...whileห่วง

ตอนนี้มีอีกจอหนึ่งและมีหลายลูปในโปรแกรมนั้น พวกเขาทั้งหมดอยู่ในรูปแบบ:

do
{
    GetProspectiveResult();
}
while (!ProspectIsGood());

1

เป็นโครงสร้างที่พบได้บ่อยในเซิร์ฟเวอร์ / ผู้บริโภค:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      REPEAT
          process
      UNTIL(wait for work(0 timeout) indicates no work)
      do what is supposed to be done at end of busy period.
   ENDIF
ENDDO

REPEAT UNTIL(cond)เป็นdo {...} while(!cond)

บางครั้งการรอทำงาน (0) อาจทำให้ CPU ถูกกว่าอย่างชาญฉลาด (แม้การกำจัดการคำนวณระยะหมดเวลาอาจเป็นการปรับปรุงด้วยอัตราการมาถึงที่สูงมาก) ยิ่งไปกว่านั้นยังมีผลทฤษฎีการจัดคิวจำนวนมากที่ทำให้จำนวนที่ให้บริการในช่วงเวลาที่วุ่นวายเป็นสถิติที่สำคัญ (ดูตัวอย่าง Kleinrock - เล่ม 1)

ในทำนองเดียวกัน:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      set throttle
      REPEAT
          process
      UNTIL(--throttle<0 **OR** wait for work(0 timeout) indicates no work)
   ENDIF
   check for and do other (perhaps polled) work.
ENDDO

ซึ่งcheck for and do other workอาจมีราคาแพงมากที่จะใส่ในลูปหลักหรืออาจเป็นเคอร์เนลที่ไม่รองรับการทำงานwaitany(waitcontrol*,n)ประเภทที่มีประสิทธิภาพหรือบางทีอาจเป็นสถานการณ์ที่คิวที่จัดลำดับความสำคัญอาจทำให้งานอื่น ๆ อดอาหารและใช้เค้นเป็นตัวควบคุมความอดอยาก

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

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


1

นี่เป็นความคิดเห็นส่วนตัวของฉัน แต่คำถามนี้ขอคำตอบที่มีรากฐานมาจากประสบการณ์:

  • ฉันเขียนโปรแกรมในภาษา C มา 38 ปีแล้วและฉันไม่เคยใช้do/ whileวนซ้ำในรหัสปกติ

  • การใช้งานที่น่าสนใจเพียงอย่างเดียวสำหรับโครงสร้างนี้คือในมาโครที่สามารถรวมคำสั่งหลาย ๆ คำสั่งไว้ในคำสั่งเดียวผ่านทางไฟล์ do { multiple statements } while (0)

  • ฉันได้เห็นตัวอย่างจำนวนนับไม่ถ้วนของdo/ whileลูปที่มีการตรวจจับข้อผิดพลาดปลอมหรือการเรียกฟังก์ชันซ้ำซ้อน

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

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

คุณสามารถหลีกเลี่ยงการวนซ้ำประเภทนี้ได้อย่างง่ายดาย: ใช้ a for (;;) { ... }และเพิ่มการทดสอบการเลิกจ้างที่จำเป็นตามความเหมาะสม เป็นเรื่องธรรมดาที่ต้องมีการทดสอบดังกล่าวมากกว่าหนึ่งครั้ง

นี่คือตัวอย่างคลาสสิก:

/* skip the line */
do {
    c = getc(fp);
} while (c != '\n');

การดำเนินการนี้จะล้มเหลวหากไฟล์ไม่ได้ลงท้ายด้วยขึ้นบรรทัดใหม่ ตัวอย่างที่ไม่สำคัญของไฟล์ดังกล่าวคือไฟล์ว่าง

เวอร์ชันที่ดีกว่าคือ:

int c;  // another classic bug is to define c as char.
while ((c = getc(fp)) != EOF && c != '\n')
    continue;

อีกทางเลือกหนึ่งเวอร์ชันนี้ยังซ่อนcตัวแปร:

for (;;) {
    int c = getc(fp);
    if (c == EOF || c == '\n')
        break;
}

ลองค้นหาwhile (c != '\n');ในเครื่องมือค้นหาใด ๆ และคุณจะพบข้อบกพร่องเช่นนี้ (สืบค้นเมื่อ 24 มิถุนายน 2017):

ในftp://ftp.dante.de/tex-archive/biblio/tib/src/streams.cฟังก์ชันgetword(stream,p,ignore)มีdo/ whileและมีข้อบกพร่องอย่างน้อย 2 ข้อเพียงพอ:

  • cถูกกำหนดให้เป็นcharและ
  • มีโอกาสที่จะวนซ้ำไม่สิ้นสุด while (c!='\n') c=getc(stream);

สรุป: หลีกเลี่ยงdo/ whileวนซ้ำและมองหาจุดบกพร่องเมื่อคุณเห็น


1
ฉันชอบหลีกเลี่ยงwhile() {}ลูปเพราะพวกเขามีความปลอดภัยมากขึ้นในแง่ของการตรวจสอบเบื้องต้นจึงมีแนวโน้มที่จะทำให้คุณ "สมองออก" ขี้เกียจที่จะคิดว่าในขั้นตอนวิธีการที่ดีกว่าใส่ตันของการตรวจสอบข้อผิดพลาด unnesesary, อื่น ๆ .. "การขาดการdo{}while()ใช้งาน" เป็น สัญญาณของความไม่ดี (ไร้สมอง) หรือโปรแกรมเมอร์มือใหม่สร้างคุณภาพที่ต่ำลงและโค้ดที่ช้าลง ดังนั้นฉันจึงถามตัวเองก่อนว่า "เป็นกรณีที่เคร่งครัด () {} หรือไม่" ถ้าไม่ได้ - ฉันก็จะพยายามที่จะเขียนทำในขณะที่ห่วงแม้มันอาจจะต้องมีการคิดและการป้อนข้อมูลเพิ่มเติมความถูกต้อง
xakepp35

ฉันเข้าใจคำตอบของคุณ แต่ฉันสามารถนึกถึงสถานการณ์ที่เป็นไปได้ซึ่งสิ่งนี้จะดีกว่า กรุณาดูที่ในขณะที่: prnt.sc/v2zy04หรือทำในขณะที่: prnt.sc/v2zyka ฉันไม่ได้เป็นโปรแกรมเมอร์มานานเท่าที่คุณมี แต่ฉันไม่พบจุดบกพร่องในนั้น ค่อนข้างชัดเจนว่า do while นั้นสะอาดกว่าเพราะไม่ต้องการการตรวจสอบเพิ่มเติมในขณะที่จะเข้าสู่ลูป หากเรากำลังพูดถึงการเพิ่มประสิทธิภาพโค้ดฉันจะบอกว่ามันค่อนข้างสะอาด
Roy Berris

@RoyBerris: ตัวอย่างของคุณน่าสนใจ ในโปรแกรม C ฟังก์ชันที่ใช้ภายในลูปจะต้องมีการทดสอบเพิ่มเติมเพื่อให้แน่ใจว่าไม่ล้มเหลว สิ่งนี้จะเพิ่มความยุ่งเหยิงและbreakหรือreturnข้อความเพิ่มเติม การเปลี่ยนdo/ whileลูปเป็นfor(;;)ลูปให้สอดคล้องกับ IMHO มากขึ้น การเหยียดหยามของฉันที่มีต่อคำพูดนี้คล้ายกับการปฏิเสธที่จะใช้strncpy() แม้ในบางกรณีที่จะเป็นเครื่องมือที่เหมาะสม: อย่าปล่อยให้ผู้อ่านทั่วไปจินตนาการว่าสิ่งก่อสร้างเหล่านี้ไม่เป็นอันตรายเพราะในกรณีส่วนใหญ่เป็นแหล่งที่มาของข้อบกพร่องที่หายาก .
chqrlie

@chqrlie เห็นคำตอบเดิมเกี่ยวกับภาษา C ใด ๆ ฉันเดาว่าทั้งสองคำตอบจะทำ C # นั้น "ประหยัด" มากเมื่อเทียบกับรุ่นก่อน ๆ ดังนั้นในทางเทคนิคแล้วมันจะเร็วกว่าเมื่อใช้ do while
Roy Berris

0

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

ฉันเข้าใจว่าคุณมาจากไหน แต่do-whileเป็นสิ่งที่ไม่ค่อยมีใครใช้และฉันไม่เคยใช้เอง คุณไม่ได้ทำผิด

คุณไม่ได้ทำผิด นั่นเหมือนกับการบอกว่ามีคนทำผิดเพราะไม่เคยใช้ของbyteดั้งเดิมมาก่อน ไม่ใช่ที่ใช้กันทั่วไป


0

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

สิ่งนี้ช่วยให้ผู้ใช้สามารถทดลองใช้อินพุตต่างๆได้หากต้องการ

do
{
   int input = GetInt("Enter any integer");
   // Do something with input.
}
while (GetBool("Go again?"));

ฉันสงสัยว่านักพัฒนาซอฟต์แวร์ใช้do/ whileน้อยลงในทุกวันนี้ตอนนี้แทบทุกโปรแกรมภายใต้ดวงอาทิตย์มี GUI บางประเภท มันสมเหตุสมผลมากขึ้นกับแอพคอนโซลเนื่องจากจำเป็นต้องรีเฟรชเอาต์พุตอย่างต่อเนื่องเพื่อให้คำแนะนำหรือแจ้งให้ผู้ใช้ทราบข้อมูลใหม่ ในทางตรงกันข้ามด้วย GUI ข้อความที่ให้ข้อมูลนั้นแก่ผู้ใช้สามารถนั่งบนแบบฟอร์มและไม่จำเป็นต้องทำซ้ำโดยใช้โปรแกรม


0

ฉันใช้ do-while ลูปตลอดเวลาเมื่ออ่านในไฟล์ ฉันทำงานกับไฟล์ข้อความจำนวนมากที่มีความคิดเห็นในส่วนหัว:

# some comments
# some more comments
column1 column2
  1.234   5.678
  9.012   3.456
    ...     ...

ฉันจะใช้ลูป do-while เพื่ออ่านจนถึงบรรทัด "column1 column2" เพื่อที่ฉันจะได้มองหาคอลัมน์ที่สนใจ นี่คือ pseudocode:

do {
    line = read_line();
} while ( line[0] == '#');
/* parse line */

จากนั้นฉันจะวนซ้ำสักครู่เพื่ออ่านไฟล์ที่เหลือ


การสนับสนุนความคิดเห็นที่ใดก็ได้ในไฟล์จะเป็นเรื่องเล็กน้อย (และทำให้โค้ดโดยรวมง่ายขึ้น) หากคุณวางif (line[0]=='#') continue;ทันทีหลังจากที่read_lineโทรเข้าหลักในขณะที่วนซ้ำ ...
R .. GitHub STOP HELPING ICE

ฉันไม่เห็นว่าฉันจะนำคำแนะนำของคุณไปใช้ในการค้นหาส่วนหัวได้อย่างไร (dang ไม่สามารถหาวิธีจัดรูปแบบโค้ดในความคิดเห็นได้โปรดช่วยด้วย!) header = false; ในขณะที่ (! header) {line = read_line (); ถ้า (บรรทัด [0] == '#') ดำเนินการต่อ; ส่วนหัว = จริง; } ชัดเจนกว่า / ง่ายกว่าสำหรับคุณ?
บิน

0

โครงการเขียนโปรแกรมในโรงเรียนของฉันหลายโครงการใช้การโต้ตอบที่ขับเคลื่อนด้วยเมนูข้อความ เกือบทั้งหมดใช้บางอย่างเช่นตรรกะต่อไปนี้สำหรับขั้นตอนหลัก:

do
    display options
    get choice
    perform action appropriate to choice
while choice is something other than exit

ตั้งแต่สมัยเรียนฉันพบว่าฉันใช้ while ลูปบ่อยขึ้น


0

หนึ่งในแอปพลิเคชันที่ฉันเคยเห็นอยู่ใน Oracle เมื่อเราดูชุดผลลัพธ์

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


0

ฉันเคยใช้มันในฟังก์ชันที่ส่งคืนตำแหน่งอักขระถัดไปในสตริง utf-8:

char *next_utf8_character(const char *txt)
{
    if (!txt || *txt == '\0')
        return txt;

    do {
        txt++;
    } while (((signed char) *txt) < 0 && (((unsigned char) *txt) & 0xc0) == 0xc0)

    return (char *)txt;
}

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


*(unsigned char *)txt-0x80U<0x40ซึ่งเป็นวิธีที่น่ารังเกียจของการเขียน
R .. GitHub STOP HELPING ICE

0

อินพุตคอนโซลทุกประเภททำงานได้ดีกับ do-while เนื่องจากคุณพร้อมต์ในครั้งแรกและแจ้งใหม่ทุกครั้งที่การตรวจสอบอินพุตล้มเหลว


0

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

กรณีที่ 1: while

string fileName = string.Empty, fullPath = string.Empty;

while (string.IsNullOrEmpty(fileName) || File.Exists(fullPath))
{
    fileName = Guid.NewGuid().ToString() + fileExtension;
    fullPath = Path.Combine(uploadDirectory, fileName);
}

กรณีที่ 2: do while

string fileName = string.Empty, fullPath = string.Empty;

do
{
    fileName = Guid.NewGuid().ToString() + fileExtension;
    fullPath = Path.Combine(uploadDirectory, fileName);
}
while (File.Exists(fullPath));

จะมีสองสิ่งที่เหมือนกัน แต่มีความแตกต่างพื้นฐานอย่างหนึ่งนั่นคือ while ต้องการคำสั่งพิเศษเพื่อเข้าสู่ while ซึ่งน่าเกลียดเพราะสมมติว่าทุกสถานการณ์ที่เป็นไปได้ของGuidชั้นเรียนได้ถูกดำเนินการไปแล้วยกเว้นตัวแปรเดียว ซึ่งหมายความว่าฉันจะต้องวนรอบ5,316,911,983,139,663,491,615,228,241,121,400,000ครั้ง ทุกครั้งที่ฉันไปถึงจุดสิ้นสุดของคำสั่ง while ฉันจะต้องทำการstring.IsNullOrEmpty(fileName)ตรวจสอบ ดังนั้นนี่จะใช้เวลาเล็กน้อย CPU ทำงานเพียงเล็กน้อย แต่ทำภารกิจเล็ก ๆ น้อย ๆ เท่าที่จะเป็นไปได้ในGuidชั้นเรียนและเรากำลังพูดถึงชั่วโมงวันเดือนหรือเวลาพิเศษ?

แน่นอนว่านี่เป็นตัวอย่างที่รุนแรงเพราะคุณอาจไม่เห็นสิ่งนี้ในการผลิต แต่ถ้าเราคิดเกี่ยวกับอัลกอริทึมของ YouTube เป็นไปได้ดีมากที่พวกเขาจะพบกับการสร้าง ID ที่มีการใช้ ID บางส่วนไปแล้ว ดังนั้นจึงเป็นโครงการขนาดใหญ่และการเพิ่มประสิทธิภาพ



-1

ฉันวิ่งข้ามสิ่งนี้ในขณะที่ค้นคว้าเกี่ยวกับลูปที่เหมาะสมเพื่อใช้กับสถานการณ์ที่ฉันมี ฉันเชื่อว่าสิ่งนี้จะตอบสนองสถานการณ์ทั่วไปได้อย่างเต็มที่โดยที่ do .. ในขณะที่ loop เป็นการใช้งานที่ดีกว่า while loop (ภาษา C # เนื่องจากคุณระบุว่าเป็นหลักในการทำงานของคุณ)

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

เมื่อใช้ข้อมูลนี้ฉันต้องการส่งคืนแต่ละแถวไปยังรายการจากนั้นหยุดเมื่อไม่มีข้อมูลให้ส่งคืน A Do ... แม้ว่าการวนซ้ำจะทำงานได้ดีที่สุดในสถานการณ์นี้เนื่องจากมั่นใจได้ว่าการเพิ่มรายการในรายการจะเกิดขึ้นก่อนที่จะตรวจสอบว่ามีแถวอื่น เหตุผลที่ต้องทำก่อนการตรวจสอบ while (เงื่อนไข) ก็คือเมื่อตรวจสอบมันก็ก้าวหน้าเช่นกัน การใช้ while loop ในสถานการณ์นี้จะทำให้ข้ามแถวแรกเนื่องจากลักษณะของฟังก์ชันนั้น ๆ

ในระยะสั้น:

สิ่งนี้ใช้ไม่ได้ในสถานการณ์ของฉัน

    //This will skip the first row because Read() returns true after advancing.
    while (_read.NextResult())
           {
               list.Add(_read.GetValue(0).ToString());
           }

   return list;

นี่จะ.

    //This will make sure the currently read row is added before advancing.
    do
        {
            list.Add(_read.GetValue(0).ToString());
        } 
        while (_read.NextResult());

    return list;

การใช้งาน SQLDataReader จะซ้อนกันลูป สายในจะเรียกRead()และควรเป็นลูป while เนื่องจากRead()สายแรกเข้าถึงแถวแรก สายนอกจะเรียกNextResult()และควรเป็น do-while เนื่องจากชุดข้อมูลผลลัพธ์แรกใช้งานได้ก่อนการNextResult()โทรครั้งแรก ข้อมูลโค้ดไม่สมเหตุสมผลมากนักโดยเฉพาะอย่างยิ่งเนื่องจากความคิดเห็นทั้งสองไม่ตรงกับรหัสและไม่ถูกต้อง
Ben Voigt

-1
Console.WriteLine("hoeveel keer moet je de zin schrijven?");
        int aantal = Convert.ToInt32(Console.ReadLine());
        int counter = 0;

        while ( counter <= aantal)
        {
            Console.WriteLine("Ik mag geen stiften gooien");
            counter = counter + 1;

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