Perulangan berhitung yang kita bahas di chapter sebelumnya cocok untuk skema yang jumlahnya diketahui. Pekerjaan sehari-hari lebih sering mengiterasi data yang sudah tersedia: daftar nama pelanggan, stok barang, isi teks, hingga pesan antar-goroutine. Go menggabungkan seluruh kebutuhan itu dalam satu bentuk: for range. Pada chapter ini kita mengiterasi slice, map, dan string secara langsung, lalu belajar mengamankan urutan map yang diacak Go — kejutan paling umum bagi pemula. Slice dan map dibedah tuntas pada Section Array, Slice, dan Map
; di sini kita cukup memakainya sebagai koleksi nilai.
range pada Slice dan Array #
Bentuk paling umum mengiterasi koleksi berurutan dengan dua variabel balikan: indeks dan nilai pada posisi tersebut. Loop berjalan dari elemen pertama sampai terakhir, sekali per elemen:
for indeks, nama := range buah {
fmt.Println(indeks, nama)
}Ketika indeks tidak dibutuhkan, kita menggantinya dengan blank identifier _ agar kompilator tidak menolak variabel tak terpakai. Sebaliknya, saat hanya butuh indeks, cukup tulis satu variabel: for indeks := range buah.
range pada Map dan Urutan yang Diacak #
Map menghasilkan pasangan kunci-nilai pada tiap iterasi. Masalahnya, spesifikasi Go sengaja tidak menjanjikan urutan apa pun: setiap eksekusi program boleh menghasilkan urutan kunci yang berbeda, bahkan antar-eksekusi dalam program yang sama. Perilaku ini memaksa kita tidak mengandalkan urutan map. Untuk output yang stabil — misalnya laporan yang harus terurut menurut abjad — urutkan kunci lebih dulu dengan idiom slices.Sorted(maps.Keys(stok)): fungsi maps.Keys mengalirkan seluruh kunci, dan slices.Sorted mengembalikannya sebagai slice yang sudah terurut.
range pada String #
String di Go adalah rangkaian byte UTF-8, dan for range pada string menghasilkan dua nilai: posisi byte saat ini dan satu rune (karakter Unicode) yang didekode dari posisi tersebut. Rune di sini adalah konsep yang sudah kita kenal di chapter String dan Rune
. Akibat pengodean UTF-8, karakter non-ASCII memakan lebih dari satu byte — posisi byte bisa “melompat” dan jumlah byte tidak sama dengan jumlah karakter.
Program Utuh: Empat Sumber Iterasi #
Program berikut mengiterasi slice, map terurut, string beraksen, lalu menjumlahkan seluruh nilai map. Berkas range-demo.go pada bagian bawah halaman memuat program yang sama:
package main
import (
"fmt"
"maps"
"slices"
)
func main() {
buah := []string{"jeruk", "mangga", "pisang"}
for indeks, nama := range buah {
fmt.Printf("buah[%d] = %s\n", indeks, nama)
}
stok := map[string]int{
"jeruk": 12,
"mangga": 8,
"pisang": 15,
}
for _, nama := range slices.Sorted(maps.Keys(stok)) {
fmt.Printf("stok %s: %d\n", nama, stok[nama])
}
kata := "café"
for posisi, huruf := range kata {
fmt.Printf("byte ke-%d: %q\n", posisi, huruf)
}
fmt.Println("panjang kata dalam byte:", len(kata))
total := 0
for _, jumlah := range stok {
total += jumlah
}
fmt.Println("total stok:", total)
}Jalankan program dari direktori chapter dengan perintah berikut:
go run range-demo.goOutput yang Dihasilkan:
buah[0] = jeruk
buah[1] = mangga
buah[2] = pisang
stok jeruk: 12
stok mangga: 8
stok pisang: 15
byte ke-0: 'c'
byte ke-1: 'a'
byte ke-2: 'f'
byte ke-3: 'é'
panjang kata dalam byte: 5
total stok: 35Mari kita telaah baris demi baris program di atas:
- Baris 13 (
buah := []string{...}): membuat slice berisi tiga nama buah. Iterasi pertama menghasilkan pasangan indeks-nilai0 "jeruk"hingga2 "pisang". - Baris 22-24 (
for _, nama := range slices.Sorted(...)): mengiterasi kunci mapstokdalam urutan abjad yang dijamin stabil. Blank identifier_membuang indeks; nilai diambil kembali denganstok[nama]. - Baris 26-30 (
kata := "café"dan loop string): empat karakter dicetak satu per satu. Loop menghasilkan rune yang didekode pada tiap posisi byte, bukan byte mentah. - Baris 31 (
len(kata)): melaporkan panjang string dalam satuan byte, yaitu 5. Runeémenempati byte ke-3 dan ke-4, sehingga iterasi terakhir berposisi 3 lalu loop berhenti — jumlah rune (4) dan jumlah byte (5) memang berbeda. - Baris 33-37 (
total := 0dan loop penjumlahan): menjumlahkan seluruh nilai map lewat blank identifier untuk kunci. Urutan iterasi map yang acak tidak memengaruhi hasil karena penjumlahan tidak peduli urutan.
range pada Channel #
for range juga bekerja pada channel: loop menerima satu nilai dari channel pada tiap iterasi dan berhenti otomatis ketika channel ditutup. Pola ini menjadi tulang punggung pemrograman konkuren di Go. Karena channel melibatkan goroutine, kita membahasnya tuntas pada chapter Channel
di Section Concurrency.
Dengan for dan range, kita sudah menguasai mesin perulangan Go. Tinggal dua alat kendali di dalam loop yang belum dibahas: break untuk berhenti lebih awal dan continue untuk melewati iterasi — keduanya topik chapter berikutnya.
Referensi #
- Spesifikasi Go: For statements
— bagian
fordengan klausarangeuntuk semua jenis koleksi. - Dokumentasi package slices
— fungsi
Sorteddan kawan-kawannya. - Dokumentasi package maps
— fungsi
Keysyang mengalirkan kunci sebuah map.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
range-demo.go
Unduh berkaspackage main
import (
"fmt"
"maps"
"slices"
)
func main() {
buah := []string{"jeruk", "mangga", "pisang"}
for indeks, nama := range buah {
fmt.Printf("buah[%d] = %s\n", indeks, nama)
}
stok := map[string]int{
"jeruk": 12,
"mangga": 8,
"pisang": 15,
}
for _, nama := range slices.Sorted(maps.Keys(stok)) {
fmt.Printf("stok %s: %d\n", nama, stok[nama])
}
kata := "café"
for posisi, huruf := range kata {
fmt.Printf("byte ke-%d: %q\n", posisi, huruf)
}
fmt.Println("panjang kata dalam byte:", len(kata))
total := 0
for _, jumlah := range stok {
total += jumlah
}
fmt.Println("total stok:", total)
}