Setiap program yang mengolah teks melakukan tiga hal berulang: membaca sebagian string, menggabungkan potongan, dan mengubah tampilannya. Di banyak bahasa pemrograman, ketiga hal itu dilakukan dengan mengganti karakter langsung di tempat. Go memilih pendekatan berbeda: string bersifat immutable — isinya tidak dapat diubah setelah string dibuat. Pada chapter ini kita akan membuktikan aturan tersebut lewat percobaan baca-tulis, membaca pesan error compiler, lalu mempelajari cara idiomatik membangun string baru.
Membaca Byte di dalam String #
String di Go adalah rangkaian byte yang diindeks mulai dari nol. Operator indeks s[0] mengambil satu byte pada posisi pertama, dan hasilnya bertipe byte (alias dari uint8), bukan string. Membaca byte dengan cara ini sepenuhnya legal karena operasi baca tidak mengubah isi string:
s := "Halo"
fmt.Println(s[0], string(s[0]))Output yang Dihasilkan:
72 HAngka 72 adalah kode numerik huruf H menurut tabel ASCII, sedangkan konversi string(s[0]) mengubah byte tersebut kembali menjadi string satu karakter. Perlu dicatat bahwa indeks string selalu menghitung byte, bukan karakter — fakta ini penting saat teks memuat karakter multibyte, dan kita bedah tuntas pada chapter UTF-8 dan Unicode
.
Penugasan Byte Ditolak Kompilator #
Sekarang kita coba kebalikannya: mengganti huruf pertama sebuah string dengan huruf lain. Berkas error-immutable.go pada folder chapter ini sengaja berisi penugasan s[0] = 'M':
package main
import "fmt"
func main() {
s := "Halo, Go!"
s[0] = 'M'
fmt.Println(s)
}Jalankan berkas tersebut untuk melihat penolakan compiler:
go run error-immutable.goOutput yang Dihasilkan:
# command-line-arguments
./error-immutable.go:7:2: cannot assign to s[0] (neither addressable nor a map index expression)Program tidak pernah berjalan: kompilasi berhenti dengan exit code 1. Baris pertama output, # command-line-arguments, adalah nama package sementara yang dibentuk go run saat kita menjalankan satu berkas. Baris kedua adalah pesan errornya: hasil indeks string bukan lokasi memori yang dapat dituju penugasan, sehingga byte string tidak bisa ditulis. Redakan pesan bisa berbeda antar versi Go, tetapi maknanya tetap: hanya elemen slice, array, dan map yang boleh menjadi sasaran assignment lewat indeks.
Membangun String Baru dengan Slicing dan Penggabungan #
Karena isi string tidak bisa diubah, mengganti teks berarti membuat string baru. Cara paling sederhana adalah mengiris string lama dengan operator slicing, lalu merangkai potongannya dengan operator +:
s := "Halo, Go!"
baru := s[:4] + ", Dunia " + s[6:]
fmt.Println(baru)Output yang Dihasilkan:
Halo, Dunia Go!Ekspresi s[:4] membentuk string Halo dari empat byte pertama, s[6:] mengambil sisa mulai byte keenam (Go!), dan operator + merangkai semuanya menjadi string baru. Variabel s tetap memuat Halo, Go! karena penggabungan tidak pernah menyentuh operand aslinya. Pola yang sama berlaku pada operator +=: setiap penugasan mengalokasikan string baru dan menyalin seluruh isi lama plus tambahannya, sehingga tiga kali pesan += "..." menghasilkan tiga salinan berukuran bertambah.
Konversi Bolak-Balik ke []byte #
Jika kita benar-benar perlu mengubah karakter di tempat, Go menyediakan pintu keluar yang jujur: konversi ke []byte. Konversi ini menyalin isi string ke slice byte baru yang isinya boleh dimutasi:
b := []byte("Halo")
b[0] = 'M'
fmt.Println(string(b))Output yang Dihasilkan:
MaloSlice b berdiri sendiri terpisah dari string asalnya, sehingga mengganti b[0] hanya mengubah salinan. Konversi string(b) menyalin byte kembali menjadi string baru — alurnya bolak-balik, dua penyalinan. Perpindahan string ↔ []byte ini menjadi kunci saat bekerja dengan data byte hasil pembacaan berkas, sebagaimana dibahas pada chapter Package bytes
.
Program Utuh #
Berkas immutable-demo.go menggabungkan seluruh percobaan di atas dalam satu program yang dapat dijalankan dari direktori chapter:
package main
import "fmt"
func main() {
s := "Halo, Go!"
// Membaca byte pada indeks 0: diperbolehkan.
fmt.Println("kode byte :", s[0])
fmt.Println("huruf :", string(s[0]))
// String baru dibangun dari potongan string lama.
depan := s[:4]
belakang := s[6:]
baru := depan + ", Dunia " + belakang
fmt.Println("baru :", baru)
// Operator += membuat alokasi string baru setiap kali.
pesan := "Stok"
pesan += " gudang"
pesan += " penuh"
fmt.Println("pesan :", pesan)
// Konversi bolak-balik []byte: isi slice boleh diubah.
b := []byte(s)
b[0] = 'M'
fmt.Println("diubah :", string(b))
fmt.Println("asli :", s)
}go run immutable-demo.goOutput yang Dihasilkan:
kode byte : 72
huruf : H
baru : Halo, Dunia Go!
pesan : Stok gudang penuh
diubah : Malo, Go!
asli : Halo, Go!Mari kita telaah baris demi baris program di atas:
- Baris 6 (
s := "Halo, Go!"): mendeklarasikan string sembilan byte yang menjadi bahan percobaan; sejak baris ini isisterkunci. - Baris 9-10 (
fmt.Println("kode byte ...")): membacas[0]sebagai byte (72) dan sebagai string (H) — operasi baca indeks berjalan normal. - Baris 13-16 (
depan := s[:4]dst.): merangkai string baruHalo, Dunia Go!dari dua irisan dan satu penggabungan; operand lama tetap utuh. - Baris 19-22 (
pesan += ...): memperluas string stok tiga kali; setiap+=membuat salinan baru hingga terbentukStok gudang penuh. - Baris 25-28 (
b := []byte(s)dst.): menyalin string ke slice byte lalu mengubah byte pertama menjadiM; baris terakhir menegaskansasli masihHalo, Go!.
Immutability membuat perilaku string mudah diprediksi: string yang sama dipakai di dua tempat tidak akan saling merusak. Imbasnya, pertanyaan “berapa panjang string” tidak lagi sesederhana hitungan byte ketika teks memuat aksen atau huruf kanji — pertanyaan itulah yang kita jawab pada chapter UTF-8 dan Unicode .
Referensi #
- Spesifikasi Go: String types — definisi resmi string sebagai rangkaian byte immutable.
- Blog Go: Strings, bytes, runes and characters — penjelasan mendalam model internal string oleh tim Go.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
error-immutable.go
Unduh berkaspackage main
import "fmt"
func main() {
s := "Halo, Go!"
s[0] = 'M'
fmt.Println(s)
}
immutable-demo.go
Unduh berkaspackage main
import "fmt"
func main() {
s := "Halo, Go!"
// Membaca byte pada indeks 0: diperbolehkan.
fmt.Println("kode byte :", s[0])
fmt.Println("huruf :", string(s[0]))
// String baru dibangun dari potongan string lama.
depan := s[:4]
belakang := s[6:]
baru := depan + ", Dunia " + belakang
fmt.Println("baru :", baru)
// Operator += membuat alokasi string baru setiap kali.
pesan := "Stok"
pesan += " gudang"
pesan += " penuh"
fmt.Println("pesan :", pesan)
// Konversi bolak-balik []byte: isi slice boleh diubah.
b := []byte(s)
b[0] = 'M'
fmt.Println("diubah :", string(b))
fmt.Println("asli :", s)
}