Array dan slice sama-sama menyimpan banyak nilai bertipe sama secara berurutan, dan isinya diambil lewat index yang mulai dari 0. Bedanya: jumlah slot array tetap, slice bisa bertambah. Bayangin Warung Bakso Mas Bimo. Mejanya ada 3 dan dipaku ke lantai: mau meja keempat berarti bongkar warung. Itu array. Buku nota pesanannya bisa terus ditulisi, dan kalau halamannya penuh, Mas Bimo pindah ke buku yang lebih tebal lalu menyalin semua catatan lama. Itu slice.
🧪 Tebakan cepat:
pesanan := []string{"Bakso urat", "Mie ayam", "Es teh"}, lalusalinan := pesanan, lalusalinan[0] = "Bakso telur". Apa isipesanansekarang: masihBakso uratdi depan, atau ikut jadiBakso telur? Tebak dulu, jawabannya ada di bagian "Slice berbagi array di belakangnya".
Array: jumlah slotnya tetap
meja := [3]string{"Sari", "Andi", "Dina"}
fmt.Println(meja) // [Sari Andi Dina]
fmt.Println(meja[0]) // Sari
fmt.Println(len(meja)) // 3
cadangan := meja
cadangan[0] = "Rudi"
fmt.Println(meja, cadangan) // [Sari Andi Dina] [Rudi Andi Dina]
[3]stringartinya 3 slot, masing-masing berisi string. Angka 3 itu bagian dari tipenya:[3]stringdan[4]stringtipe yang beda, dan ukurannya gak bisa berubah.meja[0]slot pertama,meja[2]slot terakhir.len(meja)jumlah slotnya, 3.- Array yang belum diisi berisi zero value:
var porsi [3]intadalah[0 0 0]. - Array adalah value:
cadangan := mejamenyalin ketiga isinya ke array baru. Mengubahcadangangak menyentuhmeja.
Slice: daftar yang bisa bertambah
pesanan := []string{"Bakso urat", "Mie ayam", "Es teh"}
fmt.Println(len(pesanan), cap(pesanan)) // 3 3
pesanan = append(pesanan, "Kerupuk")
fmt.Println(pesanan) // [Bakso urat Mie ayam Es teh Kerupuk]
fmt.Println(len(pesanan), cap(pesanan)) // 4 6
[]stringtanpa angka di kurung siku: itu slice. Dalam praktik, slice jauh lebih sering dipakai daripada array.append(slice, item)menambah item di belakang dan mengembalikan slice hasilnya, jadi tampung lagi:pesanan = append(...). Beberapa item sekaligus juga bisa:angka = append(angka, 40, 50).lenjumlah isinya sekarang.cap(kapasitas) jumlah slot di array tempat isinya disimpan.
Di belakang tiap slice ada sebuah array. Selama masih ada slot kosong, append langsung mengisinya. Kalau sudah penuh, Go bikin array baru yang lebih besar, menyalin isi lama ke sana, baru menambah item barunya:
| Sesudah | len |
cap |
Yang terjadi |
|---|---|---|---|
| awal | 3 | 3 | array 3 slot, penuh |
append "Kerupuk" |
4 | 6 | penuh, jadi pindah ke array baru 6 slot |
append "Es jeruk" |
5 | 6 | ada slot kosong, langsung diisi |
append "Teh panas" |
6 | 6 | slot terakhir terisi |
append "Air" |
7 | 12 | penuh lagi, pindah ke array 12 slot |
Untuk slice kecil kapasitasnya kira-kira dua kali lipat. Angka persisnya urusan runtime Go, jadi jangan dijadikan patokan. Kalau sudah tahu kira-kira butuh berapa, siapkan dari awal: make([]int, 0, 10) bikin slice kosong (len 0) dengan cap 10.
Slicing: ambil potongan dengan [awal:akhir]
angka := []int{10, 20, 30, 40, 50}
fmt.Println(angka[1:4]) // [20 30 40]
fmt.Println(angka[:3]) // [10 20 30]
fmt.Println(angka[3:]) // [40 50]
angka[1:4]mengambil index 1, 2, dan 3. Index awal ikut, index akhir gak ikut, jadi panjangnya 4 - 1 = 3.- Awal dikosongkan berarti dari index 0. Akhir dikosongkan berarti sampai habis.
Slice berbagi array di belakangnya
Slice gak memegang isinya sendiri. Dia cuma jendela ke sebuah array: penunjuk ke array itu, plus len dan cap. salinan := pesanan menyalin jendelanya, bukan isinya, jadi dua-duanya melihat array yang sama:
pesanan := []string{"Bakso urat", "Mie ayam", "Es teh"}
salinan := pesanan
salinan[0] = "Bakso telur"
fmt.Println(pesanan) // [Bakso telur Mie ayam Es teh]
pesanan ikut berubah. Itu jawaban tebakannya, dan kebalikan dari array tadi. Slicing juga begitu: dengan a := []int{1, 2, 3, 4, 5} dan b := a[1:3], slot b[0] adalah slot a[1] yang sama, jadi b[0] = 99 membuat fmt.Println(a) mencetak [1 99 3 4 5].
Begitu append pindah ke array baru, keduanya berpisah: slice yang di-append menunjuk ke array baru, slice lainnya masih ke array lama. Perubahan di satu gak kelihatan lagi di yang lain.
Index di luar batas: panic
Index yang valid cuma 0 sampai len - 1. Lewat dari itu, program berhenti dengan panic:
pesanan := []string{"Bakso urat", "Mie ayam", "Es teh"}
i := 5
fmt.Println(pesanan[i])
panic: runtime error: index out of range [5] with length 3
goroutine 1 [running]:
main.main()
/app/main.go:8 +0x1d
exit status 2
- Baris pertama yang penting: index 5 diminta, panjangnya cuma 3. Index 3 pun sudah panic.
- Baris-baris sesudahnya menunjuk file dan baris tempat panic terjadi. Kode di bawahnya gak pernah jalan.
- Kalau index-nya angka langsung dan panjangnya sudah pasti, Go menangkapnya waktu compile.
meja[5]di array[3]stringgagal denganinvalid argument: index 5 out of bounds [0:3].
💡 append bisa menimpa isi slice lain
Kalau potongan masih punya slot sisa di array yang sama, append menulis ke slot itu, dan slice lain yang memakai slot tersebut ikut berubah:
a := []int{1, 2, 3, 4, 5}
c := a[:2] // [1 2], tapi cap-nya 5
c = append(c, 77) // ditulis ke slot a[2]
fmt.Println(a) // [1 2 77 4 5]
Butuh salinan yang benar-benar terpisah? Salin isinya ke slice baru: b := append([]int{}, a[1:3]...), atau b := make([]int, 2) lalu copy(b, a[1:3]).
⚠️ Jebakan yang sering ketemu
appendtanpa ditampung.append(angka, 40)saja gagal compile denganappend(angka, 40) (value of type []int) is not used. Tulisangka = append(angka, 40).- Mengira slice disalin seperti array.
salinan := pesananberbagi isi. Array yang disalin, bukan slice. - Batas akhir slicing.
angka[1:3]cuma 2 item. Untuk index 1 sampai 3, tulisangka[1:4]. - Index terakhir. Slice 3 item punya index 0, 1, 2.
pesanan[3]panic.
TL;DR: Array [3]string punya jumlah slot tetap dan disalin utuh saat di-assign. Slice []string bisa bertambah dengan x = append(x, item) (hasilnya wajib ditampung), punya len (jumlah isi) dan cap (slot di array belakangnya), dan pindah ke array baru yang lebih besar saat penuh. x[awal:akhir] mengambil potongan tanpa index akhir. Slice yang di-assign atau dipotong berbagi array yang sama, jadi perubahan lewat satu kelihatan di yang lain. Index di luar 0 sampai len - 1 bikin panic: index out of range [5] with length 3.