Go'da ternary operatörü yoktur. cond ? a : b yoktur. Deyimsel karşılığı bir if ifadesidir:
Değişkeni varsayılan değerle tanımlayın, sonra if içinde değiştirin. İki dalın da iş yapması gerektiğinde if/else kullanın:
var fee int
if member {
fee = 0
} else {
fee = computeFee(order)
}
Go Onu Neden Dışarıda Bıraktı
Go SSS'si bunu doğrudan yanıtlar: tasarımcılar ?: operatörünün anlaşılmaz derecede karmaşık ifadeler oluşturmak için çok sık kullanıldığını görmüşler ve if/else'in daha uzun olsa da tartışmasız daha anlaşılır olduğuna karar vermişlerdir. Bir dilin tek bir koşullu kontrol akışı yapısına ihtiyacı vardır.
Pratikte eksik operatör her kullanımda iki üç satıra mal olur ve a ? b ? c : d : e gibi iç içe ifadelerin bütün bir kategorisini ortadan kaldırır.
Bunun Yerine Erken Dönmek
Bir fonksiyonun içinde en temiz biçim çoğu zaman değişkeni tamamen atlar:
Koşulu küçük, adlandırılmış bir fonksiyona çekmek çoğu zaman en iyi cevaptır: çağrı noktası istediğiniz ternary gibi okunur ve fonksiyon adı koşulun ne anlama geldiğini belgeler.
cmp.Or ile Varsayılan Değerler (Go 1.22)
Diğer dillerdeki en yaygın ternary "bu değeri kullan, boşsa bir yedeği": name ? name : "anonymous" ya da JavaScript'te name || "anonymous". Go 1.22 tam olarak bunun için cmp.Or'u ekledi. Kendi tipinin sıfır değeri olmayan ilk argümanı döndürür:
Sıfır değeri "eksik" olarak ele alır, bu yüzden "port bilerek 0" ile "port ayarlanmadı"yı ayırt edemez. Sıfır geçerli bir değer olduğunda bir pointer, ayrı bir bool ya da açık bir if kullanın.
Generic bir If Yardımcısı ve Tuzağı
Generics (Go 1.18) ile ternary'ye benzeyen bir fonksiyon yazabilirsiniz:
func If[T any](cond bool, a, b T) T {
if cond {
return a
}
return b
}
status := If(ok, "pass", "fail")
Basit değerler için çalışır ve bazı kod tabanları onu kullanır. Ama bu bir ternary operatörü değildir ve fark önemlidir. Go bir fonksiyonu çağırmadan önce tüm argümanları değerlendirir, bu yüzden hem a hem de b her zaman hesaplanır:
İlk çağrı hem "a"'yı hem de "b"'yi hesaplar, ikincisi ise koşul false olmasına rağmen nil pointer dereference ile panic olur. Gerçek bir ternary yalnızca seçilen tarafı değerlendirirdi. Bu yüzden:
- Bir taraf bir pointer'ı dereference ediyorsa, bir slice'ı indeksliyorsa ya da var olmayabilecek bir map girdisini okuyorsa böyle bir yardımcıyı asla kullanmayın.
- Bir taraf pahalıysa ya da yan etkileri varsa asla kullanmayın.
- Ucuz, güvenli değerler için çalışır, ama birçok Go kod incelemecisi yine de düz
if'i isteyecektir.
Dalları fonksiyonlar aktararak tembel yapabilirsiniz, If(ok, func() string { return a }, func() string { return b }), ama o noktada if ifadesi daha kısadır.
Diğer Hileler ve Neden Kaçınılmalı
Map araması. map[bool]string{true: "yes", false: "no"}[ok] çalışır, her değerlendirmede bir map oluşturup hash'ler ve iki değeri de değerlendirir. Bir merak konusudur, bir deyim değil.
Hemen çağrılan fonksiyon. Yerinde çağrılan anonim bir fonksiyon size bir ifade verir:
label := func() string {
if n > 0 {
return "positive"
}
return "non-positive"
}()
Bu gerçekten tembel değerlendirir ve bir ifadenin (statement) gidemeyeceği bir bileşik literal'in içinde ara sıra işe yarar. Çoğu zaman değeri literal'den hemen önce bir değişkende hesaplamak daha anlaşılırdır.
Bir Karşılık Seçmek
| Durum | Kullanın |
|---|---|
| İki değer arasında seçim | varsayılan değer, sonra if |
| İki dal da hesaplama gerektiriyor | if/else |
| Değer fonksiyonun sonucunu belirliyor | erken return |
| Bir değer boş olduğunda yedek | cmp.Or(value, fallback) |
| Üç ya da daha fazla durum | switch |
| Anlamı olan tekrarlanan bir koşul | küçük, adlandırılmış bir fonksiyon |
Koşullu bir ifade ekleme önerileri Go'nun issue takipçisinde düzenli olarak gündeme gelir ve şimdiye kadar reddedilmiştir. if'i yazın.
Sıkça Sorulan Sorular
Go'da ternary operatörü var mı?
Hayır. Go'da cond ? a : b ifadesi yoktur. Go SSS'si, tasarımcıların onu okunması zor ifadeler kurmak için çok sık kullanıldığı için dışarıda bıraktığını söyler. Bunun yerine bir if/else ifadesi kullanın.
Go'da tek satırlık koşullu atama nasıl yazılır?
Önce varsayılanı atayın, sonra üzerine yazın:
label := "odd"
if n%2 == 0 {
label = "even"
}
Deyimsel karşılık budur. gofmt bir if gövdesini tek satıra koymaz, bu yüzden her zaman en az üç satır tutar.
Go'da generic bir ternary fonksiyonu yazabilir miyim?
Evet: func If[T any](cond bool, a, b T) T { if cond { return a }; return b }. Sorun şu ki Go bir fonksiyonu çağırmadan önce her argümanı değerlendirir, bu yüzden hem a hem de b hesaplanır. If(p != nil, p.Name, "") yine nil bir p'yi dereference eder ve panic olur. Gerçek bir ternary yalnızca bir tarafı değerlendirirdi.
Go'da bir string boşsa varsayılan değer nasıl ayarlanır?
Go 1.22'den beri cmp.Or(name, "anonymous") sıfır değer olmayan ilk argümanı döndürür, yani name "" değilse name'i verir. Karşılaştırılabilir her tip için çalışır ve her fonksiyon çağrısı gibi tüm argümanlarını değerlendirir.