لا تملك Go الكلمة while. اكتب for يليها شرط، وتحصل على حلقة while:
يُفحص الشرط قبل كل تكرار، فإذا كان خاطئًا في البداية لا يُنفَّذ الجسم أبدًا. هذا مطابق لـ while (balance < 2000) في C أو Java أو JavaScript، دون الأقواس والكلمة المفتاحية. اختار مصمّمو Go كلمة حلقة واحدة لكل أشكال الحلقات؛ راجع صفحة حلقة for لأشكالها الأربعة كلها.
while(true): الحلقة اللانهائية
احذف الشرط كليًا فتدور الحلقة حتى ينهيها شيء بداخلها:
for { } هي الكتابة المعتادة. تُترجم for true { } أيضًا، لكنها تبدو وكأن كاتبها قادم من لغة أخرى.
أربعة أشياء تنهي الحلقة اللانهائية: break (تخرج من الحلقة)، وreturn (تخرج من الدالة)، وpanic، وos.Exit. البرنامج الذي تقع main فيه داخل for {} دون أي من هذه يعمل حتى يُقتل، وهذا صحيح تمامًا لخادم أو عامل.
do-while
تنفّذ do-while الجسم مرة واحدة قبل فحص الشرط. لا تملك Go صياغة مخصّصة لها. ضع الفحص في نهاية حلقة لا نهائية:
يُنفَّذ الجسم مرة واحدة على الأقل مهما حدث، وهذه هي الخاصية المميّزة لـ do-while. يستخدم مصدر الأرقام العشوائية بذرة ثابتة فتكون المخرجات واحدة في كل تشغيل؛ استخدم rand.IntN دون مصدر ذي بذرة للعشوائية الحقيقية.
شكل ثانٍ يُبقي الشرط في الترويسة بفرض المرور الأول:
for first := true; first || condition(); first = false {
// body
}
يعمل، لكن الحلقة اللانهائية مع break في النهاية أسهل قراءة، وهي ما تفعله معظم شيفرات Go.
القراءة حتى النهاية
أشيع حلقة while في شيفرات Go الحقيقية تقرأ المدخلات حتى تنفد. صُمّم bufio.Scanner لذلك: تعيد Scan القيمة false عند نهاية المدخلات أو عند خطأ، فهي شرط الحلقة:
استبدل strings.NewReader(input) بـ os.Stdin فتقرأ الحلقة نفسها مدخلات المستخدم سطرًا بسطر. افحص scanner.Err() بعد الحلقة: إعادة Scan للقيمة false لا تخبرك هل انتهت المدخلات بشكل طبيعي أم فشلت.
break وcontinue
كلتاهما تعملان في كل أشكال for:
في الحلقة ذات الشرط وحده تقفز continue مباشرة إلى الشرط. وهذا يسهّل خطأ خفيًا: إذا حُدّث العدّاد في أسفل الجسم، فإن continue فوقه تتخطّى التحديث فلا تنتهي الحلقة أبدًا. حدّث العدّاد في الأعلى، كما في المثال، أو استخدم for بثلاثة أجزاء التي تُنفَّذ عبارة post فيها حتى بعد continue.
انتظار شيء ما
الحلقة التي تنتظر شرطًا يجب أن تتوقّف أو تنام، لا أن تدور:
// Wrong: burns a CPU core while waiting
for !ready {
}
// Better: poll with a delay
for !isReady() {
time.Sleep(100 * time.Millisecond)
}
استطلاع متغيّر عادي تكتب فيه goroutine أخرى سباق بيانات أيضًا. بين الـ goroutines انتظر على قناة أو sync.WaitGroup أو sync.Cond بدلًا من ذلك، أو استخدم select مع مؤقّت. ولحلقات إعادة المحاولة ذات الحد، فضّل for بعدّاد حتى لا تدور الحلقة إلى الأبد:
for attempt := 1; attempt <= 5; attempt++ {
if err := connect(); err == nil {
break
}
time.Sleep(time.Duration(attempt) * 200 * time.Millisecond)
}
أخطاء شائعة
- نسيان تغيير متغيّر الشرط.
for i < 10 { fmt.Println(i) }لا تنتهي أبدًا. كل حلقة while تحتاج شيئًا في الجسم يقرّبها من الخروج. - كتابة
while. تعطيwhile x < 5 {}الرسالةsyntax error: unexpected name x at end of statement، لأنwhileليست كلمة مفتاحية؛ فيقرؤها المترجم كاسم عادي. - الأقواس بحكم العادة.
for (x < 5) {}تُترجم، ويزيلgofmtالأقواس. - تعريف المتغيّر في الحلقة.
for n := 10; n > 0 {}خطأ صياغة؛ الحلقة ذات جزء التهيئة تحتاج الأجزاء الثلاثة. عرّفnقبل الحلقة، أو اكتب الشكل الكامل ذا الأجزاء الثلاثة.
الأسئلة الشائعة
هل تملك Go حلقة while؟
ليس ككلمة مفتاحية. تستخدم Go الكلمة for لكل حلقة، وfor مع شرط فقط هي حلقة while بالضبط:
for count < 10 {
count++
}
يُفحص الشرط قبل كل تكرار، تمامًا مثل while (count < 10) في C أو Java.
كيف أكتب while(true) في Go؟
اكتب for دون أي شيء بعدها: for { ... }. تدور حتى تنهيها break أو return أو panic أو os.Exit. تُترجم for true { ... } أيضًا، لكن for { } هي الشكل المعتاد.
كيف أكتب حلقة do-while في Go؟
استخدم حلقة لا نهائية وضع فحص الشرط في نهاية الجسم:
for {
// body runs at least once
if !condition {
break
}
}
يُنفَّذ الجسم دائمًا مرة واحدة قبل اختبار الشرط، وهذا معنى do-while.