Chapter sebelumnya menunjukkan bahwa string adalah deret byte UTF-8 yang tidak bisa diubah. Pertanyaan berikutnya pun muncul: bagaimana cara memproses teks yang isinya perlu diubah byte demi byte, misalnya data mentah dari jaringan atau isi berkas? Jawabannya adalah tipe []byte — potongan memori byte yang bisa dimodifikasi — beserta konversi bolak-baliknya dengan string. Pada chapter ini kita akan mengamati isi memori teks dalam tiga tampilan (desimal, heksadesimal, kutip), mengubah byte secara langsung, lalu memeriksa keabsahan data UTF-8.
Tipe byte dan []byte #
Tipe byte adalah alias resmi untuk uint8: satu byte menyimpan angka 0 sampai 255. Tipe []byte adalah deret byte yang bisa diubah (mutable), sedangkan string adalah deret byte yang bersifat baca-saja. Keduanya saling dikonversi dengan sintaks konversi biasa:
data := []byte("Halo") // string menjadi []byte
teks := string(data) // []byte menjadi stringKonversi ini menyalin isi datanya, bukan sekadar mengganti label. Akibatnya, mengubah elemen data tidak mengubah string asal — perilaku yang akan kita buktikan pada program utuh.
Membaca Byte dalam Tiga Tampilan #
Package fmt menyediakan tiga jendela untuk mengamati deret byte yang sama. Verb default mencetak angka desimal setiap byte, verb %x mencetak heksadesimal, dan verb %q mencetak tampilan teksnya:
data := []byte("Halo")
fmt.Println(data) // [72 97 108 111]
fmt.Printf("%x\n", data) // 48616c6f
fmt.Printf("%q\n", data) // "Halo"Angka 72 dan heksadesimal 0x48 adalah byte yang sama — huruf H dalam encoding ASCII/UTF-8. Huruf a menjadi 97 desimal atau 0x61 heksadesimal, dan seterusnya untuk seluruh isi string.
Mengubah Byte Secara Langsung #
Elemen []byte bisa ditugaskan ulang satu per satu karena potongan ini mutable. Data 'M' yang ditulis dengan petik tunggal adalah literal rune; Go mengonversinya ke nilai byte 77 secara otomatis saat ditugaskan ke elemen []byte. Setelah perubahan, konversi string(data) menghasilkan teks baru — string lama tetap utuh di memori karena salinan datanya terpisah.
Program Utuh #
Berkas byte-demo.go memperagakan konversi, tiga tampilan, mutasi, dan validasi UTF-8. Jalankan berkas tersebut dari direktori chapter:
go run byte-demo.gopackage main
import (
"fmt"
"unicode/utf8"
)
func main() {
pesan := "Halo, Siti!"
data := []byte(pesan)
fmt.Println("string :", pesan)
fmt.Println("[]byte :", data)
fmt.Printf("hex : %x\n", data)
fmt.Printf("quoted : %q\n", data)
data[0] = 'M'
fmt.Println("setelah ubah :", string(data))
fmt.Println("pesan asli :", pesan)
fmt.Println("data valid UTF-8 :", utf8.Valid(data))
fmt.Println("byte rusak valid :", utf8.Valid([]byte{0xff, 0xfe}))
}Output yang Dihasilkan:
string : Halo, Siti!
[]byte : [72 97 108 111 44 32 83 105 116 105 33]
hex : 48616c6f2c205369746921
quoted : "Halo, Siti!"
setelah ubah : Malo, Siti!
pesan asli : Halo, Siti!
data valid UTF-8 : true
byte rusak valid : falseMari kita telaah baris demi baris program di atas:
- Baris 11 (
data := []byte(pesan)): mengonversi string menjadi[]bytesekaligus menyalin isinya ke memori baru yang bisa diubah. - Baris 13–16: mencetak data yang sama dalam tiga tampilan — 11 angka desimal, 22 digit heksadesimal, dan teks aslinya; koma (44) dan spasi (32) ikut terlihat sebagai byte.
- Baris 18 (
data[0] = 'M'): mengganti byte pertama dari 72 (H) menjadi 77 (M) secara langsung di memori. - Baris 19–20: memperlihatkan hasil mutasi
"Malo, Siti!"sekaligus bukti bahwapesantetap"Halo, Siti!"— konversi menyalin data, tidak membagi memori. - Baris 22 (
utf8.Valid(data)): memeriksa apakah seluruh byte membentuk encoding UTF-8 yang sah, hasilnyatrue. - Baris 23 (
utf8.Valid([]byte{0xff, 0xfe})): menguji dua byte acak 0xff dan 0xfe yang bukan pola UTF-8 valid, hasilnyafalse.
Validasi Data Mentah #
Fungsi utf8.Valid adalah gerbang pemeriksaan sebelum byte mentah dipercaya sebagai teks. Data dari jaringan, berkas biner, atau sensor bisa berisi urutan byte yang tidak membentuk karakter UTF-8 sah, dan mencetaknya begitu saja menghasilkan teks rusak berisi simbol acak. Dengan pemeriksaan utf8.Valid(data) terlebih dahulu, program bisa menolak data rusak sebelum diproses lebih jauh.
Dua tampilan teks — string dan byte — kini sudah kita kuasai bersama caranya berpindah. Selanjutnya kita mundur selangkah untuk memahami bagaimana compiler menentukan tipe variabel tanpa kita menuliskannya secara eksplisit.
Referensi #
- Blog Go: Strings, bytes, runes and characters — representasi string dan byte di memori.
- Dokumentasi package unicode/utf8
— fungsi
ValiddanRuneCountInString. - Spesifikasi Go: Conversions — aturan konversi antar tipe, termasuk string dan []byte.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
byte-demo.go
Unduh berkaspackage main
import (
"fmt"
"unicode/utf8"
)
func main() {
pesan := "Halo, Siti!"
data := []byte(pesan)
fmt.Println("string :", pesan)
fmt.Println("[]byte :", data)
fmt.Printf("hex : %x\n", data)
fmt.Printf("quoted : %q\n", data)
data[0] = 'M'
fmt.Println("setelah ubah :", string(data))
fmt.Println("pesan asli :", pesan)
fmt.Println("data valid UTF-8 :", utf8.Valid(data))
fmt.Println("byte rusak valid :", utf8.Valid([]byte{0xff, 0xfe}))
}