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:

go
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:

go
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:

bash
go run range-demo.go

Output yang Dihasilkan:

text
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: 35

Mari kita telaah baris demi baris program di atas:

  1. Baris 13 (buah := []string{...}): membuat slice berisi tiga nama buah. Iterasi pertama menghasilkan pasangan indeks-nilai 0 "jeruk" hingga 2 "pisang".
  2. Baris 22-24 (for _, nama := range slices.Sorted(...)): mengiterasi kunci map stok dalam urutan abjad yang dijamin stabil. Blank identifier _ membuang indeks; nilai diambil kembali dengan stok[nama].
  3. 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.
  4. 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.
  5. Baris 33-37 (total := 0 dan 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 #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

range-demo.go

Unduh berkas
go
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)
}