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
ifbiasa.
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
| Situasi | Pakai |
|---|---|
| Memilih di antara dua nilai | nilai default, lalu if |
| Kedua cabang butuh perhitungan | if/else |
| Nilai menentukan hasil fungsi | return lebih awal |
| Nilai cadangan saat sebuah nilai kosong | cmp.Or(value, fallback) |
| Tiga case atau lebih | switch |
| Kondisi berulang yang punya makna | fungsi 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.