Menu

Operator Ternary di Golang: Kenapa Go Tidak Punya dan Penggantinya

Go tidak punya operator ternary (cond ? a : b). Halaman ini menjelaskan alasannya, menunjukkan pengganti idiomatis dengan if/else, cmp.Or untuk nilai default, dan fungsi helper generic beserta jebakan yang membuatnya berbeda dari ternary sungguhan.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Go tidak punya operator ternary. Tidak ada cond ? a : b. Pengganti yang idiomatis adalah pernyataan if:

Deklarasikan variabel dengan nilai default, lalu ubah nilainya di dalam if. Kalau kedua cabang sama-sama butuh perhitungan, pakai if/else:

var fee int
if member {
	fee = 0
} else {
	fee = computeFee(order)
}

Kenapa Go tidak memasukkannya

FAQ Go menjawab ini secara langsung: para perancangnya terlalu sering melihat operator ?: dipakai untuk membuat ekspresi yang rumit dan sulit dipahami, lalu memutuskan bahwa if/else, walaupun lebih panjang, jelas lebih mudah dibaca. Sebuah bahasa cukup punya satu konstruksi alur kontrol bersyarat.

Dalam praktiknya, ketiadaan operator ini hanya menambah dua atau tiga baris setiap kali dipakai, dan menghilangkan seluruh jenis ekspresi bersarang seperti a ? b ? c : d : e.

Return lebih awal sebagai gantinya

Di dalam fungsi, bentuk yang paling rapi sering kali tidak butuh variabel sama sekali:

Memindahkan kondisi ke dalam fungsi kecil yang punya nama sering menjadi jawaban terbaik: tempat pemanggilannya terbaca seperti ternary yang kamu inginkan, dan nama fungsinya menjelaskan arti kondisi itu.

Nilai default dengan cmp.Or (Go 1.22)

Ternary yang paling umum di bahasa lain adalah "pakai nilai ini, atau nilai cadangan kalau kosong": name ? name : "anonymous", atau name || "anonymous" di JavaScript. Go 1.22 menambahkan cmp.Or tepat untuk ini. Fungsi ini mengembalikan argumen pertama yang bukan zero value dari tipenya:

Fungsi ini menganggap zero value sebagai "tidak ada", jadi ia tidak bisa membedakan "port sengaja bernilai 0" dari "port belum diisi". Kalau nol adalah nilai yang sah, pakai pointer, bool terpisah, atau if yang eksplisit.

Helper If yang generic, dan jebakannya

Dengan generic (Go 1.18), kamu bisa menulis fungsi yang terlihat seperti ternary:

func If[T any](cond bool, a, b T) T {
	if cond {
		return a
	}
	return b
}

status := If(ok, "pass", "fail")

Fungsi ini bekerja untuk nilai sederhana, dan sebagian codebase memakainya. Tetapi ini bukan operator ternary, dan perbedaannya penting. Go mengevaluasi semua argumen sebelum memanggil fungsi, jadi a dan b selalu dihitung:

Panggilan pertama menghitung "a" sekaligus "b", dan panggilan kedua panic dengan nil pointer dereference, walaupun kondisinya false. Ternary sungguhan hanya mengevaluasi sisi yang dipilih. Jadi:

  • Jangan pernah memakai helper seperti ini kalau salah satu sisinya melakukan dereference pada pointer, mengakses indeks slice, atau membaca entri map yang mungkin tidak ada.
  • Jangan pernah memakainya kalau salah satu sisinya mahal atau punya efek samping.
  • Untuk nilai yang murah dan aman, helper ini bisa dipakai, tetapi banyak reviewer Go tetap akan meminta if biasa.

Kamu bisa membuat cabangnya dievaluasi belakangan dengan mengirim fungsi, If(ok, func() string { return a }, func() string { return b }), tetapi pada titik itu pernyataan if justru lebih pendek.

Trik lain, dan kenapa sebaiknya dihindari

Lookup map. map[bool]string{true: "yes", false: "no"}[ok] memang bisa, tetapi membangun map dan menghitung hash setiap kali dievaluasi, serta mengevaluasi kedua nilainya. Ini sekadar keanehan, bukan idiom.

Fungsi yang langsung dipanggil. Fungsi anonim yang dipanggil di tempat memberimu sebuah ekspresi:

label := func() string {
	if n > 0 {
		return "positive"
	}
	return "non-positive"
}()

Cara ini memang mengevaluasi secara belakangan, dan sesekali membantu di dalam composite literal yang tidak bisa diisi pernyataan. Hampir setiap saat, menghitung nilainya ke dalam variabel tepat sebelum literal itu lebih jelas.

Memilih pengganti

SituasiPakai
Memilih di antara dua nilainilai default, lalu if
Kedua cabang butuh perhitunganif/else
Nilai menentukan hasil fungsireturn lebih awal
Nilai cadangan saat sebuah nilai kosongcmp.Or(value, fallback)
Tiga case atau lebihswitch
Kondisi berulang yang punya maknafungsi kecil yang punya nama

Usulan untuk menambahkan ekspresi bersyarat rutin muncul di issue tracker Go dan sejauh ini selalu ditolak. Tulis saja if-nya.

Pertanyaan yang sering diajukan

Apakah Go punya operator ternary?

Tidak. Go tidak punya ekspresi cond ? a : b. FAQ Go menyebutkan bahwa para perancangnya sengaja tidak memasukkannya karena operator ini terlalu sering dipakai untuk membuat ekspresi yang sulit dibaca. Pakai pernyataan if/else sebagai gantinya.

Bagaimana cara menulis assignment bersyarat dalam satu baris di Go?

Isi nilai default lebih dulu, lalu timpa:

label := "odd"
if n%2 == 0 {
	label = "even"
}

Itulah pengganti yang idiomatis. gofmt tidak akan menaruh badan if dalam satu baris, jadi kode ini selalu butuh paling sedikit tiga baris.

Apakah saya bisa menulis fungsi ternary generic di Go?

Bisa: func If[T any](cond bool, a, b T) T { if cond { return a }; return b }. Masalahnya, Go mengevaluasi setiap argumen sebelum memanggil fungsi, jadi a dan b sama-sama dihitung. If(p != nil, p.Name, "") tetap melakukan dereference pada p yang nil dan panic. Ternary sungguhan hanya mengevaluasi satu sisi.

Bagaimana cara mengisi nilai default jika sebuah string kosong di Go?

Sejak Go 1.22, cmp.Or(name, "anonymous") mengembalikan argumen pertama yang bukan zero value, jadi hasilnya name kecuali name bernilai "". Fungsi ini bisa dipakai untuk tipe apa pun yang bisa dibandingkan, dan seperti pemanggilan fungsi lainnya, ia mengevaluasi semua argumennya.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai