BAB 37: Konversi Tipe Data
Pelajari cara mengonversi antar tipe data di Go: konversi numerik eksplisit, konversi string menggunakan package strconv, konversi byte slice, dan type assertion untuk interface.
Di Bab 7, kamu sudah melihat sekilas bagaimana Go menolak konversi tipe implisit — compiler akan menolak float64(25) + int(10) karena keduanya berbeda tipe, meski secara logika penjumlahan itu masuk akal. Pendekatan ini disengaja: Go ingin kamu tahu persis kapan dan bagaimana tipe berubah, bukan membiarkan compiler menebak niatmu.
Tapi penolakan ini bukan tanpa jalan keluar. Go menyediakan mekanisme konversi yang lengkap dan terkontrol — dari konversi antar tipe numerik, konversi string menggunakan package strconv, hingga type assertion untuk mengekstrak nilai konkret dari interface. Bab ini membahas semuanya secara sistematis.
Konversi Antar Tipe Numerik
Konversi antar tipe numerik yang kompatibel dilakukan dengan sintaks TipeTujuan(nilai). Ini adalah konversi paling sederhana dan tidak mengembalikan error.
// konversi.go
package main
import "fmt"
func main() {
stok := 47 // int
rasio := 0.85 // float64
// int ke float64 untuk operasi campuran
proyeksi := float64(stok) * rasio
fmt.Printf("proyeksi stok: %.1f\n", proyeksi)
// float64 ke int — desimal dipotong, bukan dibulatkan
stokBulat := int(proyeksi)
fmt.Printf("stok bulat: %d\n", stokBulat)
// int ke int8 — perhatikan range yang lebih sempit
var kode int8 = int8(stok)
fmt.Printf("kode: %d\n", kode)
}
proyeksi stok: 39.9
stok bulat: 39
kode: 47
Konversi dari float64 ke int memotong bagian desimal begitu saja — 39.95 menjadi 39, bukan 40. Ini bukan pembulatan, melainkan truncation.
Konversi ke tipe dengan range lebih kecil bisa mengakibatkan data terpotong tanpa peringatan. int(300) dikonversi ke int8 akan menghasilkan nilai yang salah karena int8 hanya muat sampai 127. Go tidak menghasilkan error — nilainya hanya “membungkus” di sekitar batas range.
Konversi String dan Angka
Konversi antara string dan angka membutuhkan bantuan package strconv. Casting langsung seperti string(42) tidak menghasilkan "42" — ia menghasilkan karakter dengan Unicode code point 42 (yang bukan karakter yang bisa dicetak).
Integer ke String dan Sebaliknya
strconv.Itoa mengonversi int ke string. Kebalikannya, strconv.Atoi, mengonversi string ke int — dan karena proses ini bisa gagal (jika string bukan angka valid), ia mengembalikan dua nilai: hasil dan error.
// konversi.go
package main
import (
"fmt"
"strconv"
)
func main() {
// int ke string
jumlah := 250
teks := strconv.Itoa(jumlah)
fmt.Printf("sebagai string: %q (panjang: %d)\n", teks, len(teks))
// string ke int
input := "128"
angka, err := strconv.Atoi(input)
if err != nil {
fmt.Println("gagal konversi:", err)
return
}
fmt.Printf("sebagai int: %d\n", angka)
// input tidak valid
_, err = strconv.Atoi("dua ratus")
if err != nil {
fmt.Println("error:", err)
}
}
sebagai string: "250" (panjang: 3)
sebagai int: 128
error: strconv.Atoi: parsing "dua ratus": invalid syntax
Float ke String dan Sebaliknya
Untuk float, tersedia strconv.FormatFloat dan strconv.ParseFloat. Keduanya memberi kontrol atas format dan presisi.
// konversi.go
package main
import (
"fmt"
"strconv"
)
func main() {
harga := 189500.75
// float64 ke string: format 'f', 2 desimal, bit size 64
teks := strconv.FormatFloat(harga, 'f', 2, 64)
fmt.Printf("harga: %s\n", teks)
// format eksponensial
notasiE := strconv.FormatFloat(harga, 'e', 3, 64)
fmt.Printf("notasi E: %s\n", notasiE)
// string ke float64
input := "1750.50"
nilai, err := strconv.ParseFloat(input, 64)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("parsed: %.2f\n", nilai)
}
harga: 189500.75
notasi E: 1.895e+05
parsed: 1750.50
Parameter format 'f' menghasilkan notasi desimal biasa, 'e' menghasilkan notasi eksponensial, dan 'g' memilih yang lebih ringkas secara otomatis. Parameter presisi mengontrol jumlah digit setelah titik desimal.
Konversi dengan Basis Bilangan
strconv.ParseInt dan strconv.FormatInt mendukung konversi ke basis selain 10 — berguna saat bekerja dengan data biner, oktal, atau heksadesimal.
// konversi.go
package main
import (
"fmt"
"strconv"
)
func main() {
// desimal ke biner, oktal, hex
angka := int64(255)
fmt.Println("biner :", strconv.FormatInt(angka, 2))
fmt.Println("oktal :", strconv.FormatInt(angka, 8))
fmt.Println("hex :", strconv.FormatInt(angka, 16))
// string biner ke int64
dariBiner, _ := strconv.ParseInt("11111111", 2, 64)
fmt.Printf("dari biner: %d\n", dariBiner)
// string hex ke int64
dariHex, _ := strconv.ParseInt("ff", 16, 64)
fmt.Printf("dari hex: %d\n", dariHex)
}
biner : 11111111
oktal : 377
hex : ff
dari biner: 255
dari hex: 255
Konversi String dan Byte Slice
String di Go pada dasarnya adalah urutan byte yang immutable. Karena itu, konversi antara string dan []byte adalah operasi yang sangat umum — terutama saat bekerja dengan I/O, enkripsi, atau manipulasi data biner.
// konversi.go
package main
import "fmt"
func main() {
pesan := "Sistem Aktif"
// string ke []byte
data := []byte(pesan)
fmt.Println("bytes:", data)
// modifikasi byte (string asli tidak terpengaruh)
data[0] = 's'
fmt.Println("dimodifikasi:", string(data))
fmt.Println("asli :", pesan)
// []byte ke string
raw := []byte{71, 111, 108, 97, 110, 103}
fmt.Println("dari bytes:", string(raw))
}
bytes: [83 105 115 116 101 109 32 65 107 116 105 102]
dimodifikasi: sistem Aktif
asli : Sistem Aktif
Konversi string ke []byte membuat salinan data, bukan referensi — itulah mengapa mengubah data[0] tidak memengaruhi pesan yang asli.
Ada juga konversi string ke []rune untuk bekerja dengan karakter Unicode. []rune bekerja per karakter, sedangkan []byte bekerja per byte. Untuk teks yang mengandung karakter non-ASCII, gunakan []rune jika kamu perlu mengakses atau memanipulasi per karakter.
Type Assertion untuk Interface
Ketika sebuah nilai disimpan dalam variabel bertipe interface{} (atau any — alias yang ditambahkan sejak Go 1.18), kamu perlu type assertion untuk mengakses nilai konkretnya.
// konversi.go
package main
import "fmt"
func cetakInfo(data any) {
// type assertion langsung — bisa panic jika tipe tidak sesuai
teks, ok := data.(string)
if ok {
fmt.Printf("string dengan panjang %d: %q\n", len(teks), teks)
return
}
angka, ok := data.(int)
if ok {
fmt.Printf("integer: %d\n", angka)
return
}
fmt.Printf("tipe tidak dikenali: %T\n", data)
}
func main() {
cetakInfo("laporan bulanan")
cetakInfo(42)
cetakInfo(3.14)
}
string dengan panjang 15: "laporan bulanan"
integer: 42
tipe tidak dikenali: float64
Pola nilai, ok := data.(Tipe) disebut comma-ok assertion — aman karena tidak akan panic jika tipenya tidak sesuai. Jika ok bernilai false, variabel nilai akan berisi zero value dari Tipe yang diminta.
Type Switch
Untuk menangani banyak kemungkinan tipe sekaligus, type switch jauh lebih bersih daripada serangkaian if dengan comma-ok assertion.
// konversi.go
package main
import "fmt"
type Laporan struct {
Judul string
}
func deskripsikan(nilai any) string {
switch v := nilai.(type) {
case string:
return fmt.Sprintf("teks %d karakter", len(v))
case int:
return fmt.Sprintf("bilangan bulat %d", v)
case float64:
return fmt.Sprintf("desimal %.4f", v)
case bool:
if v {
return "kondisi benar"
}
return "kondisi salah"
case Laporan:
return fmt.Sprintf("laporan: %s", v.Judul)
case nil:
return "nilai kosong"
default:
return fmt.Sprintf("tipe tidak dikenal: %T", v)
}
}
func main() {
nilai := []any{
"kuartal tiga",
99,
98.6,
true,
Laporan{Judul: "Rekap Penjualan"},
nil,
}
for _, v := range nilai {
fmt.Println(deskripsikan(v))
}
}
teks 11 karakter
bilangan bulat 99
desimal 98.6000
kondisi benar
laporan: Rekap Penjualan
nilai kosong
Dalam type switch, variabel v secara otomatis bertipe konkret di setiap case — di case string, v bertipe string; di case int, v bertipe int. Tidak perlu assertion tambahan.
Latihan
Latihan 1 — Kalkulator tipe campuran:
Buat fungsi hitungRata(nilai []string) (float64, error) yang menerima slice string berisi angka (misalnya ["85", "92", "78"]), mengonversi setiap elemen ke float64, dan mengembalikan rata-ratanya. Kembalikan error jika ada elemen yang bukan angka valid.
Latihan 2 — Formatter angka:
Tulis fungsi formatAngka(n int) string yang mengonversi integer ke representasi string dalam empat basis: desimal, biner, oktal, dan heksadesimal, lalu mengembalikan keempatnya dalam satu string terformat. Contoh output: "42 | 101010 | 52 | 2a".
Latihan 3 — Prosesor data dinamis:
Buat fungsi proses(data []any) map[string]int yang menerima slice bertipe any dan mengembalikan peta jumlah elemen per tipe. Contoh: jika input berisi 3 string, 2 int, dan 1 float64, kembalikan {"string": 3, "int": 2, "float64": 1}. Gunakan type switch untuk mendeteksi tipe setiap elemen.
Konversi tipe adalah salah satu mekanisme yang memperlihatkan filosofi Go paling jelas: eksplisit lebih baik dari implisit. Kamu tahu persis kapan data berubah bentuk, di baris mana, dan apa risikonya. Bersama semua yang sudah kamu pelajari — dari goroutine dan channel hingga standard library dan konversi tipe — kamu kini punya fondasi yang solid untuk mulai membangun program Go yang nyata.