summaryrefslogtreecommitdiff
path: root/_content/blog/slices-intro
diff options
context:
space:
mode:
Diffstat (limited to '_content/blog/slices-intro')
-rw-r--r--_content/blog/slices-intro/go-slices-usage-and-internals_slice-1.pngbin0 -> 6334 bytes
-rw-r--r--_content/blog/slices-intro/go-slices-usage-and-internals_slice-2.pngbin0 -> 7220 bytes
-rw-r--r--_content/blog/slices-intro/go-slices-usage-and-internals_slice-3.pngbin0 -> 7303 bytes
-rw-r--r--_content/blog/slices-intro/go-slices-usage-and-internals_slice-array.pngbin0 -> 1237 bytes
-rw-r--r--_content/blog/slices-intro/go-slices-usage-and-internals_slice-struct.pngbin0 -> 3650 bytes
-rw-r--r--_content/blog/slices-intro/index.adoc399
6 files changed, 399 insertions, 0 deletions
diff --git a/_content/blog/slices-intro/go-slices-usage-and-internals_slice-1.png b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-1.png
new file mode 100644
index 0000000..ba465cf
--- /dev/null
+++ b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-1.png
Binary files differ
diff --git a/_content/blog/slices-intro/go-slices-usage-and-internals_slice-2.png b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-2.png
new file mode 100644
index 0000000..a57581e
--- /dev/null
+++ b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-2.png
Binary files differ
diff --git a/_content/blog/slices-intro/go-slices-usage-and-internals_slice-3.png b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-3.png
new file mode 100644
index 0000000..64ece5e
--- /dev/null
+++ b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-3.png
Binary files differ
diff --git a/_content/blog/slices-intro/go-slices-usage-and-internals_slice-array.png b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-array.png
new file mode 100644
index 0000000..a533702
--- /dev/null
+++ b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-array.png
Binary files differ
diff --git a/_content/blog/slices-intro/go-slices-usage-and-internals_slice-struct.png b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-struct.png
new file mode 100644
index 0000000..f9141fc
--- /dev/null
+++ b/_content/blog/slices-intro/go-slices-usage-and-internals_slice-struct.png
Binary files differ
diff --git a/_content/blog/slices-intro/index.adoc b/_content/blog/slices-intro/index.adoc
new file mode 100644
index 0000000..2dbc250
--- /dev/null
+++ b/_content/blog/slices-intro/index.adoc
@@ -0,0 +1,399 @@
+= Slice pada Go: penggunaan dan internal
+:author: Andrew Gerrand
+:date: 5 Januari 2011
+
+
+== Pendahuluan
+
+Tipe slice pada Go menyediakan cara yang mudah dan efisien untuk bekerja
+dengan seurutan data bertipe.
+Slice sama dengan array pada bahasa pemrograman lainnya, namun memiliki
+beberapa properti yang tidak biasa.
+Artikel ini akan menelaah apa itu slice dan bagaimana cara menggunakannya.
+
+
+== Array
+
+Tipe slice adalah sebuah abstraksi yang dibangun di atas tipe array, jadi
+untuk memahami slice kita harus memahami array terlebih dahulu.
+
+Definisi tipe dari sebuah array menspesifikasikan panjang dan tipe dari
+elemen.
+Contohnya, tipe `[4]int` merepresentasikan sebuah array dari empat integer.
+Ukuran dari array tetap;
+panjangnya adalah bagian dari tipenya
+(`[4]int` dan `[5]int` adalah tipe yang berbeda dan tidak kompatibel).
+Array bisa diakses dengan metode indeks pada biasanya, sehingga ekspresi
+`s[n]` berarti mengakses elemen ke-n, yang mana `n` dimulai dari nol.
+
+----
+var a [4]int
+a[0] = 1
+i := a[0]
+// i == 1
+----
+
+Array tidak perlu diinisiasi secara eksplisit;
+nilai kosong dari sebuah array siap digunakan yang setiap elemennya yaitu
+nilai kosong dari tipe array tersebut:
+
+----
+// a[2] == 0, nilai kosong dari tipe int
+----
+
+Representasi `[4]int` dalam memori yaitu empat integer yang berurutan:
+
+image:/blog/go-slices-usage-and-internals/go-slices-usage-and-internals_slice-array.png[]
+
+Array pada Go adalah nilai.
+Sebuah variabel array menyatakan keseluruhan array: ia bukan pointer ke elemen
+pertama (seperti halnya pada C).
+Hal ini berarti bahwa saat kita mengisi atau mengirim nilai array, kita akan
+membuat salinan dari isinya.
+(Untuk mengindahkan penyalinan kita bisa mengirim sebuah pointer ke array,
+namun hal ini berarti sebuah pointer ke sebuah array, bukan sebuah array.)
+Bayangkan array adalah sebuah bentuk struct dengan indeks bukan dengan
+field-field yang memiliki nama: sebuah nilai komposit yang berukuran tetap.
+
+----
+b := [2]string{"Penn", "Teller"}
+----
+
+Atau, kita bisa membuat _compiler_ menghitung elemen array secara otomatis:
+
+----
+b := [...]string{"Penn", "Teller"}
+----
+
+Dalam kedua kasus di atas, tipe dari b yaitu `[2]string`.
+
+
+== Slice
+
+Array ada gunanya, namun tidak fleksibel, sehingga kita jarang melihatnya
+dalam kode Go.
+Slice, ada di mana saja.
+Slice dibentuk dari array untuk menyediakan kemudahan dan kekuatan yang lebih.
+
+Spesifikasi tipe untuk sebuah slice yaitu `[]T`, yang mana `T` adalah tipe
+dari elemen slice.
+Tidak seperti tipe array, tipe slice tidak memiliki panjang.
+
+Sintaksis dari slice dideklarasikan seperti sintaksis array, namun tanpa
+jumlah elemen:
+
+----
+letters := []string{"a", "b", "c", "d"}
+----
+
+Sebuah slice bisa dibuat dengan fungsi bawaan `make`, yang memiliki penanda,
+
+----
+func make([]T, len, cap) []T
+----
+
+yang mana `T` yaitu tipe elemen dari slice yang akan dibuat.
+Fungsi `make` menerima sebuah tipe, panjang, dan kapasitas yang opsional.
+Saat dipanggil, `make` mengalokasikan sebuah array dan mengembalikan sebuah
+slice yang mengacu pada array tersebut.
+
+----
+var s []byte
+s = make([]byte, 5, 5)
+// s == []byte{0, 0, 0, 0, 0}
+----
+
+Bila argumen kapasitas diindahkan, ia akan sama nilainya dengan panjang yang
+dispesifikasikan.
+Berikut versi singkat dari kode yang sama:
+
+----
+s := make([]byte, 5)
+----
+
+Panjang dan kapasitas dari sebuah slice dapat diketahui menggunakan fungsi
+bawaan `len` dan `cap`.
+
+----
+len(s) == 5
+cap(s) == 5
+----
+
+Dua bagian berikut akan mendiskusikan hubungan antara panjang dan kapasitas.
+
+Nilai kosong dari sebuah slice adalah `nil`.
+Fungsi `len` dan `cap` akan mengembalikan nilai 0 untuk slice yang nil.
+
+Sebuah slice juga dapat dibentuk dengan "memotong" slice atau array.
+Pemotongan dilakukan dengan menspesifikasikan rentang setengah-terbuka dengan
+dua indeks yang dipisahkan oleh tanda titik-dua.
+Contohnya, ekspresi `b[1:4]` membuat sebuah slice yang mengikutkan elemen 1
+sampai 3 dari b (indeks dari pemotongan slice yaitu tetap dari 0 sampai 2).
+
+----
+b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
+// b[1:4] == []byte{'o', 'l', 'a'}, berbagi penyimpanan yang sama dengan b.
+----
+
+Indeks awal dan akhir dari ekspresi pemotongan slice tidak harus diisi;
+nilai bakunya yaitu nol dan panjang dari slice itu sendiri:
+
+----
+// b[:2] == []byte{'g', 'o'}
+// b[2:] == []byte{'l', 'a', 'n', 'g'}
+// b[:] == b
+----
+
+Berikut sintaksis untuk membuat sebuah slice dari sebuah array:
+
+----
+x := [3]string{"Лайка", "Белка", "Стрелка"}
+s := x[:] // sebuah slice yang mengacu penyimpanan dari x.
+----
+
+
+== Internal dari slice
+
+Sebuah slice yaitu _descriptor_ (yang mendeskripsikan) segmen dari array.
+Ia terdiri dari pointer ke array, panjang dari segmen, dan kapasitasnya
+(panjang maksimum dari segmen).
+
+image:/blog/go-slices-usage-and-internals/go-slices-usage-and-internals_slice-struct.png[]
+
+Variabel `s` yang kita buat sebelumnya dengan `make([]byte, 5)`, memiliki
+struktur seperti berikut:
+
+image:/blog/go-slices-usage-and-internals/go-slices-usage-and-internals_slice-1.png[]
+
+Panjangnya yaitu jumlah elemen yang diacu oleh slice.
+Kapasitasnya yaitu jumlah elemen pada array di belakangnya (dimulai dari
+elemen pertama yang diacu oleh pointer pada slice).
+Perbedaan antara panjang dan kapasitas akan terlihat jelas saat kita melihat
+contoh-contoh selanjutnya.
+
+Saat kita memotong slice `s`, perhatikan perubahan pada struktur data slice
+dan hubungannya dengan array di baliknya:
+
+----
+s = s[2:4]
+----
+
+image:/blog/go-slices-usage-and-internals/go-slices-usage-and-internals_slice-2.png[]
+
+Memotong slice tidak menyalin data dari slice.
+Ia membuat sebuah nilai slice yang baru yang menunjuk ke array aslinya.
+Hal ini membuat operasi slice efisien seperti memanipulasi indeks dari array.
+Oleh karena itu, mengubah _elemen_ (bukan slice itu sendiri) dari hasil
+pemotongan slice akan mengubah elemen di slice aslinya:
+
+----
+d := []byte{'r', 'o', 'a', 'd'}
+e := d[2:]
+// e == []byte{'a', 'd'}
+e[1] = 'm'
+// e == []byte{'a', 'm'}
+// d == []byte{'r', 'o', 'a', 'm'}
+----
+
+Sebelumnya kita memotong `s` dengan panjang yang lebih kecil dari
+kapasitasnya.
+Kita dapat mengembangkan `s` sampai ke kapasitasnya dengan memotongnya
+kembali:
+
+----
+s = s[:cap(s)]
+----
+
+image:/blog/go-slices-usage-and-internals/go-slices-usage-and-internals_slice-3.png[]
+
+Sebuah slice tidak dapat mengembang lebih dari kapasitasnya.
+Mencoba melakukan hal tersebut akan menyebabkan panik _runtime_, seperti saat
+melakukan pengindeksan di luar batas dari slice atau array.
+Hal yang serupa, slice tidak bisa dipotong kecil dari nol untuk mengakses
+elemen sebelumnya dalam array.
+
+
+== Mengembangkan slice (fungsi copy dan append)
+
+Untuk meningkatkan kapasitas dari sebuah slice kita harus membuat slice yang
+baru dan lebih besar dan menyalin isi dari slice asli ke dalamnya.
+Teknik ini adalah cara implementasi array secara dinamis pada bahasa
+pemrograman lain.
+Contoh selanjutnya melipatgandakan kapasitas dari `s` dengan membuat slice
+baru `t`, menyalin isi dari `s` ke `t`, dan kemudian menempatkan nilai slice
+`t` ke `s`:
+
+----
+t := make([]byte, len(s), (cap(s)+1)*2) // +1 seandainya cap(s) == 0
+for i := range s {
+ t[i] = s[i]
+}
+s = t
+----
+
+Bagian pengulangan pada operasi di atas dapat dipermudah dengan fungsi bawaan
+`copy`.
+Seperti namanya, `copy` menyalin data dari slice sumber ke slice tujuan.
+Ia mengembalikan jumlah elemen yang disalin.
+
+----
+func copy(dst, src []T) int
+----
+
+Fungsi `copy` mendukung penyalinan antara slice yang berbeda panjangnya (ia
+hanya akan menyalin sampai jumlah elemen paling kecil).
+Sebagai tambahan, `copy` dapat menangani slice sumber dan tujuan yang berbagi
+array yang sama, menangani slice yang saling timpa dengan benar.
+
+Dengan menggunakan `copy`, kita dapat menyederhanakan potongan kode di atas:
+
+----
+t := make([]byte, len(s), (cap(s)+1)*2)
+copy(t, s)
+s = t
+----
+
+Operasi umum lainnya dari slice yaitu menambahkan data ke akhir slice.
+Fungsi berikut menambahkan elemen byte ke sebuah slice dari byte,
+mengembangkan slice jika perlu, dan mengembalikan nilai slice yang diperbarui:
+
+----
+func AppendByte(slice []byte, data ...byte) []byte {
+ m := len(slice)
+ n := m + len(data)
+ if n > cap(slice) { // jika perlu, alokasi ulang.
+ // Buat alokasi dua kali lebih besar dari yang dibutuhkan,
+ // untuk penambahan nantinya.
+ newSlice := make([]byte, (n+1)*2)
+ copy(newSlice, slice)
+ slice = newSlice
+ }
+ slice = slice[0:n]
+ copy(slice[m:n], data)
+ return slice
+}
+----
+
+Kita gunakan fungsi `AppendByte` seperti berikut:
+
+----
+p := []byte{2, 3, 5}
+p = AppendByte(p, 7, 11, 13)
+// p == []byte{2, 3, 5, 7, 11, 13}
+----
+
+Fungsi seperti `AppendByte` berguna karena memberikan kontrol sepenuhnya
+dalam mengembangkan isi dari slice.
+Bergantung pada karakteristik program, fungsi tersebut bisa saja
+mengalokasikan potongan yang lebih kecil atau besar, atau mengatur batas atas
+dari ukuran realokasi.
+
+Namun kebanyakan program tidak perlu kontrol sepenuhnya, sehingga Go
+menyediakan fungsi bawaan `append` yang berguna untuk tujuan umum;
+fungsi `append` memiliki penanda
+
+----
+func append(s []T, x ...T) []T
+----
+
+Fungsi `append` menambahkan elemen-elemen `x` ke akhir dari slice `s`, dan
+mengembangkan ukuran slice jika kapasitas lebih besar dibutuhkan.
+
+----
+a := make([]int, 1)
+// a == []int{0}
+a = append(a, 1, 2, 3)
+// a == []int{0, 1, 2, 3}
+----
+
+Untuk menambahkan slice ke slice lainnya, gunakan ... untuk memperluas
+argumen kedua menjadi sebuah daftar argumen.
+
+----
+a := []string{"John", "Paul"}
+b := []string{"George", "Ringo", "Pete"}
+a = append(a, b...) // sama dengan "append(a, b[0], b[1], b[2])"
+// a == []string{"John", "Paul", "George", "Ringo", "Pete"}
+----
+
+Secara nilai kosong dari slice (`nil`) sifatnya seperti slice dengan panjang
+nol, kita dapat mendeklarasikan sebuah variabel slice dan kemudian
+menambahkan elemen-elemen dalam sebuah pengulangan:
+
+----
+// Filter mengembalikan sebuah slice baru yang menyimpan hanya elemen-elemen
+// dari s yang memenuhi fungsi fn().
+func Filter(s []int, fn func(int) bool) []int {
+ var p []int // == nil
+ for _, v := range s {
+ if fn(v) {
+ p = append(p, v)
+ }
+ }
+ return p
+}
+----
+
+
+== Kesalahan yang umum
+
+Seperti yang disebutkan sebelumnya, memotong sebuah slice tidak menyalin array
+di belakangnya.
+Array yang utuh tetap tersimpan dalam memori sampai tidak ada lagi yang
+memakainya.
+Terkadang hal ini bisa membuat program menyimpan semua data di dalam memori
+saat hanya sebagian kecil dari slice yang dibutuhkan.
+
+Sebagai contohnya, fungsi `FindDigits` berikut memuat sebuah berkas ke dalam
+memori dan mencari seurutan digit numerik yang pertama, dan mengembalikan
+urutan tersebut sebagai sebuah slice yang baru.
+
+----
+var digitRegexp = regexp.MustCompile("[0-9]+")
+
+func FindDigits(filename string) []byte {
+ b, _ := ioutil.ReadFile(filename)
+ return digitRegexp.Find(b)
+}
+----
+
+Kode di atas berjalan seperti yang tertulis, namun `[]byte` yang dikembalikan
+menunjuk ke array yang berisi seluruh berkas.
+Karena slice mengacu ke array aslinya, selama slice tersebut masih digunakan
+maka _garbage collector_ tidak dapat menghapus array;
+beberapa byte yang terpakai dari berkas menahan seluruh isi berkas di dalam
+memori.
+
+Untuk memperbaiki permasalahan ini kita dapat menyalin data yang perlu saja ke
+slice yang baru sebelum dikembalikan:
+
+----
+func CopyDigits(filename string) []byte {
+ b, _ := ioutil.ReadFile(filename)
+ b = digitRegexp.Find(b)
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+}
+----
+
+Versi lebih ringkas dari fungsi di atas dapat dibangun menggunakan `append`.
+Cara ini adalah latihan bagi pembaca.
+
+
+== Bacaan Lebih Lanjut
+
+link:/doc/effective_go.html[Efektif Go]
+berisi perlakuan lebih dalam dari
+link:/doc/effective_go.html#slices[slice]
+dan
+link:/doc/effective_go.html#arrays[array],
+dan
+link:/ref/spec/index.html[spesifikasi bahasa]
+Go mendefinisikan
+link:/ref/spec/index.html#Slice_types[slice]
+dan
+link:/ref/spec/index.html#Appending_and_copying_slices[fungsi-fungsi]
+link:/ref/spec/index.html#Making_slices_maps_and_channels[pembantu]
+link:/ref/spec/index.html#Length_and_capacity[yang berhubungan]
+dengan slice.