Menu

Golang for Döngüsü: Örneklerle Dört Biçimi

Go'nun tek bir döngü anahtar kelimesi vardır, for, ve her şeyi karşılar: üç parçalı sayaç döngüsü, yalnızca koşullu while döngüsü, sonsuz döngü ve slice'lar, map'ler, string'ler, channel'lar, tam sayılar ve fonksiyonlar üzerinde range. Ayrıca etiketli break ve continue ile Go 1.22'deki döngü değişkeni değişikliği.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Go'nun tam olarak bir döngü anahtar kelimesi vardır: for. Dört biçimi vardır ve bunlar birlikte, başka dillerde for, while, do while ya da foreach ile yazacağınız her döngüyü karşılar.

Döngü başlığının etrafına parantez konmaz ve süslü parantezler her zaman zorunludur.

Üç Parçalı Döngü

for init; condition; post {
	// body
}
  1. init döngüden önce bir kez çalışır. Genellikle i := 0 gibi kısa bir değişken tanımıdır ve o değişken yalnızca döngünün içinde vardır.
  2. condition her yinelemeden önce kontrol edilir. False olduğunda döngü biter.
  3. Gövde çalışır.
  4. post her yinelemeden sonra çalışır, genellikle i++.

i++ Go'da bir ifade (expression) değil, bir deyimdir (statement), bu yüzden post içinde i++, j-- olamaz. Bunun yerine paralel atama kullanın: i, j = i+1, j-1.

Üç parçanın hepsi isteğe bağlıdır. for ; i < 10; {} geçerlidir ve gofmt onu bir sonraki biçim olan for i < 10 {}'ye çevirir.

Yalnızca Koşullu Döngü (Go'nun while'ı)

Yalnızca bir koşulla for, başka dillerdeki while gibi davranır:

Ayrı bir do while yoktur. While döngüsü sayfası "en az bir kez çalış" davranışının nasıl elde edileceğini gösteriyor.

Sonsuz Döngüler

Arkasında hiçbir şey olmayan for sonsuza kadar döner. Ondan break, return, os.Exit ya da bir panic ile çıkın:

for {
	line, err := reader.ReadString('\n')
	if err != nil {
		break
	}
	process(line)
}

Bu, sunucular, worker'lar ve girdi döngüleri için standart biçimdir. Gövdesi boş bir for {} bir CPU çekirdeğini boşuna yakar; gerçek kodda gövde bir şey üzerinde bloklanır (bir okuma, bir channel alımı, bir select).

range Döngüleri

range bir koleksiyon üzerinde döner ve her yinelemede bir ya da iki değer verir. Bunların ne olduğu neyin üzerinde döndüğünüze bağlıdır:

Üzerinde dönülenİlk değerİkinci değer
slice ya da diziindekseleman (bir kopya)
stringbayt indeksirune (Unicode karakteri)
mapanahtardeğer
channeleleman(yok)
tam sayı n (Go 1.22)0'dan n eksi 1'e(yok)
iterator fonksiyonu (Go 1.23)fonksiyonun verdiğifonksiyonun verdiği

Çıktının gösterdiği üç ayrıntı:

  • Değer değişkeni bir kopyadır. Döngü içindeki v *= 2 slice'ı değiştirmez; elemanları değiştirmek için üçüncü döngünün yaptığı gibi nums[i] ile slice'a indeksleyin.
  • Bir string'in indeksi bir bayt konumudur. é iki bayt tutar, bu yüzden indeks 1'den 3'e atlar.
  • Map sırası bilerek rastgeledir. Go, kod ona bağımlı olamasın diye sırayı rastgele hale getirir. slices.Sorted(maps.Keys(m)) (Go 1.23) anahtarları sıralı verir.

range; channel'lar, iterator fonksiyonları ve kopyalama kuralları dahil tüm ayrıntılarıyla range sayfasında anlatılıyor.

break ve continue

break en içteki döngüyü sonlandırır. continue bir sonraki yinelemeye atlar (üç parçalı döngüde önce post çalışır):

Etiketli break ve continue

Düz bir break yalnızca en içteki döngüden çıkar. İç içe bir döngünün içinden dış döngüden çıkmak için dış döngüyü etiketleyin:

Etiket, ardından iki nokta gelen bir tanımlayıcıdır ve doğrudan for'un önüne konur. Go, kullanılmayan bir etiketi, tıpkı kullanılmayan bir değişken gibi derleme hatası olarak raporlar.

switch ve select içinde break

Bir for içinde, bir switch ya da select case'indeki break döngüden değil, switch ya da select'ten çıkar:

for {
	switch cmd := next(); cmd {
	case "quit":
		break // only exits the switch; the loop keeps running
	}
}

Bir switch ya da select içinden döngüden çıkmak için etiketli bir break ya da return kullanın.

Go 1.22'den Beri Döngü Değişkenleri

Go 1.22 döngü değişkenlerinin kapsamını değiştirdi: her yineleme artık i ve v'nin yeni bir kopyasını alıyor. Önceden tüm döngü boyunca tek bir değişken yeniden kullanılıyordu ve bu, onu yakalayan closure'ları ve goroutine'leri bozuyordu:

Go 1.22 ve sonrasında bu program 0 1 2 ve [aa bb cc] yazdırır. Eski semantikte for i := 0; i < 3; i++ ile yazılmış aynı program (tam sayı üzerinde range 1.22'den önce yoktu) 3 3 3 yazdırıyordu ve goroutine'ler paylaşılan i ve name üzerinde race'e giriyordu. Eski geçici çözüm olan, döngü gövdesinin başındaki i := i artık gerekmez.

Davranış, derleyici sürümüne göre değil, go.mod içindeki go satırına göre modül başına belirlenir. Hâlâ go 1.21 diyen bir modül, Go 1.24 ile derlense bile eski semantiği korur.

Sık Yapılan Hatalar

Kopyayı değiştirmek. for _, v := range items { v.Count++ } bir kopyayı değiştirir. items[i].Count++ kullanın ya da pointer'lardan oluşan bir slice üzerinde dönün.

Dönerken eleman eklemek. range slice'ı başta bir kez değerlendirir. Döngü içinde eklenen elemanlar ziyaret edilmez; döngü yine sonlanır ama yeni öğeleri görmez.

İleri doğru giden bir döngüde indeksle slice'tan silmek. i elemanını silmek geri kalanı sola kaydırır, bu yüzden bir sonraki eleman atlanır. Yeni bir slice oluşturun, geriye doğru dönün ya da slices.DeleteFunc kullanın.

<= ile bir fazla hatası. for i := 0; i <= len(s); i++ son turda s[len(s)]'i okur ve index out of range ile panic olur. < kullanın, daha iyisi range.

Koşulda ağır iş. Koşul her yinelemede çalışır. for i := 0; i < expensiveCount(); i++ fonksiyonu her seferinde çağırır; onu döngüden önce bir kez hesaplayın.

Sayaç olarak float kullanmak. for x := 0.0; x != 1.0; x += 0.1 hiç bitmez, çünkü 0.1'in kesin bir ikili temsili yoktur. Bir tam sayıyla sayın ve float'ı ondan hesaplayın.

Sıkça Sorulan Sorular

Go'da for döngüsü nasıl yazılır?

Klasik biçimin noktalı virgüllerle ayrılmış üç parçası vardır ve parantez kullanılmaz:

for i := 0; i < 5; i++ {
	fmt.Println(i)
}

Go 1.22'den beri 0'dan 4'e kadar sayan for i := range 5 da yazabilirsiniz. Bir slice'ı dolaşmak için for i, v := range items kullanın.

Go'da while döngüsü var mı?

while anahtar kelimesi yok, ama yalnızca koşulu olan bir for bir while döngüsüdür: for n > 0 { n /= 2 }. Koşulsuz for { ... } ise break ya da return ile çıktığınız sonsuz bir döngüdür.

Go'da bir map üzerinde nasıl döngü kurulur?

for key, value := range m { ... }. Dolaşma sırası belirtilmemiştir ve çalışma zamanı onu rastgele hale getirir, bu yüzden bir döngüden diğerine değişebilir. Ona asla güvenmeyin. Kararlı bir sıra için anahtarları toplayın, slices.Sort ile sıralayın ve sıralanmış anahtarlar üzerinde dönün.

Go'da iç içe bir döngüden nasıl çıkılır?

Dış döngünün önüne bir etiket koyun ve break'te onu belirtin: outer: for ... { for ... { if found { break outer } } }. Düz bir break yalnızca en içteki for, switch ya da select'ten çıkar. continue outer da aynı şekilde etiketli döngünün bir sonraki yinelemesine atlar.

Go 1.22'de döngü değişkenleriyle ilgili ne değişti?

Go 1.22'den önce bir for döngüsünün tüm yinelemelerce paylaşılan tek bir değişkeni vardı, bu yüzden döngüde başlatılan closure'lar ve goroutine'ler çoğu zaman hep son değeri görüyordu. Go 1.22'den beri her yineleme kendi kopyasını alır, bu yüzden i ya da v'yi bir closure içinde yakalamak beklendiği gibi çalışır. Yeni davranış, modülün go.mod dosyası go 1.22 ya da sonrasını belirttiğinde geçerlidir.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA