Aksi takdirde tek satırlık açıklama nasıl yapılır?


104

Php'de yaptığım gibi go (golang) değişken atamalı basit bir if-else ifadesi yazabilir miyim? Örneğin:

$var = ( $a > $b )? $a: $b;

Şu anda aşağıdakileri kullanmam gerekiyor:

var c int
if a > b {
    c = a
} else {
    c = b
}

Maalesef bu kontrol ifadesinin adını hatırlayamıyorum ve bilgiyi site içinde veya google arama yoluyla bulamadım. : /


4
Buna üçlü operatör denir ... ve hayır, Go'nun bir operatörü yok.
Simon Whitehead

6
Aradığınız kelimenin "üçlü" olduğuna inanıyorum
BenjaminRH


10
Sadece açıklığa kavuşturmak gerekirse, üçlü operatör herhangi bir arity 3 operatörü, yani 3 alt ifadeyi bağlayan herhangi bir operatördür. C'nin böyle tek bir operatörü vardır. Bu yüzden genellikle üçlü operatör olarak adlandırılır. Gerçek adı "koşullu operatör" dir.
2014

Yanıtlar:


132

Yorumlarda belirtildiği gibi, Go, üçlü bir gömlekleri desteklemiyor. Aklıma gelen en kısa biçim şudur:

var c int
if c = b; a > b {
    c = a
}

Ama lütfen bunu yapmayın, buna değmez ve sadece kodunuzu okuyan kişilerin kafasını karıştırır.


84
@thoroc, sezgisel olmayan bir IMHO olduğundan, gerçek hayatta muhtemelen bundan kaçınırdım, daha az okunabilirlik için 2 satırı kaydetmeye değmez.
Not_a_Golfer

14
@thoroc, lütfen Not_a_Golfer'ın ne dediğini dinle. Kendinizi göstermeye değil, bakımı yapılabilir bir yazılım yazmaya çalışmalısınız . Düzgün numaralar güzeldir, ancak kodunuzu okuyan bir sonraki kişi (birkaç ay / yıl içinde siz de dahil olmak üzere) onları takdir etmeyecektir.
kostix

3
Okunabilirlik kadar bağlıdır. Bunun daha okunaklı olduğunu düşünüyorum, ancak her şey gibi kötüye de kullanılabilir. İf bloğunun dışında ihtiyaç duyulmayan bir değişkeni bildirmeniz gerekiyorsa, bunun bir kazanan olduğunu düşünüyorum.
arjabbar

@Not_a_Golfer Sadece simetri ile okunabilirlik değil, aynı zamanda niyetin yapısal zıtlığı da derlenen kodda, hatta bazen fazladan bir başlatma için ekstra maliyetle.
Wolf

5
Oh, sevinç, Go'nun üçlü bir operatörün olmamasıyla ne kadar kazanıldığına bir bakın. Yapılan okunabilirlik yorumlarının yanı sıra, yalnızca bir dalın her zaman çalıştırıldığı ve ikincisinin ek olarak çalıştırılabildiği, tembel olarak değerlendirilen bir yapıyı değiştirdiniz.
itsbruce

29

Sıklıkla aşağıdakileri kullanıyorum:

c := b
if a > b {
    c = a
}

Temelde @ Not_a_Golfer'ınkiyle aynıdır, ancak tür çıkarımını kullanır .


4
Aynı eksiklikle: Açıkça simetrik bir gereksinim için asimetrik bir çözüm kullanırken anlayışı karmaşıklaştırırsınız.
Wolf

2
Ve tembel olarak değerlendirilmesi gereken bir yapıyı, iki daldan sadece birinin her zaman değerlendirileceği bir yapıya, bazen her ikisine de (bu durumda ilk değerlendirme gereksizdi)
itsbruce

1
Kullanım durumuna bağlı olarak, bu yine de çok yararlı olabilir. Örneğin listeningPath := "production.some.com"; if DEBUG { listeningPath := "development.some.com" }, üretim için üçlü ile aynı hız ve oldukça iyi okunabilirlik.
Levite

CPU döngüsünü kasıtlı olarak boşa harcadığımda genellikle ağlarım.
alessiosavi

28

Diğerlerinin de belirttiği gibi, Goüçlü tek gömlekleri desteklemez. Ancak, istediğinizi elde etmenize yardımcı olabilecek bir yardımcı program işlevi yazdım.

// IfThenElse evaluates a condition, if true returns the first parameter otherwise the second
func IfThenElse(condition bool, a interface{}, b interface{}) interface{} {
    if condition {
        return a
    }
    return b
}

İşte onu nasıl kullanabileceğinizi gösteren bazı test senaryoları

func TestIfThenElse(t *testing.T) {
    assert.Equal(t, IfThenElse(1 == 1, "Yes", false), "Yes")
    assert.Equal(t, IfThenElse(1 != 1, nil, 1), 1)
    assert.Equal(t, IfThenElse(1 < 2, nil, "No"), nil)
}

Eğlenmek için, aşağıdakiler gibi daha kullanışlı yardımcı fonksiyonlar yazdım:

IfThen(1 == 1, "Yes") // "Yes"
IfThen(1 != 1, "Woo") // nil
IfThen(1 < 2, "Less") // "Less"

IfThenElse(1 == 1, "Yes", false) // "Yes"
IfThenElse(1 != 1, nil, 1)       // 1
IfThenElse(1 < 2, nil, "No")     // nil

DefaultIfNil(nil, nil)  // nil
DefaultIfNil(nil, "")   // ""
DefaultIfNil("A", "B")  // "A"
DefaultIfNil(true, "B") // true
DefaultIfNil(1, false)  // 1

FirstNonNil(nil, nil)                // nil
FirstNonNil(nil, "")                 // ""
FirstNonNil("A", "B")                // "A"
FirstNonNil(true, "B")               // true
FirstNonNil(1, false)                // 1
FirstNonNil(nil, nil, nil, 10)       // 10
FirstNonNil(nil, nil, nil, nil, nil) // nil
FirstNonNil()                        // nil

Bunlardan herhangi birini kullanmak isterseniz burada bulabilirsiniz https://github.com/shomali11/util


12

Doğru yanıtı gösterdiğin için teşekkürler.

Golang SSS'yi (duh) kontrol ettim ve açıkça belirtiyor ki, bu dilde mevcut değil:

Go'nun?: Operatörü var mı?

Go'da üçlü form yoktur. Aynı sonucu elde etmek için aşağıdakileri kullanabilirsiniz:

if expr {
    n = trueVal
} else {
    n = falseVal
}

Konuyla ilgilenebilecek ek bilgiler bulundu:


o bir satırda da mümkündür: var c int; if a > b { c = a } else { c = b }? Ancak okuyucunun rekreasyonu için hafif bir blok oluşturmak için 5 satırda tutmanızı öneririm;)
Wolf

7

Olası bir yolu olmadığını ben kontrol ediyorum bir harita, basit kullanarak sadece bir satırda bunu yapmak a > bÇünkü eğer trueben atama ediyorum ciçin aaksib

c := map[bool]int{true: a, false: b}[a > b]

Ancak, bu harika görünüyor, ancak bazı durumlarda değerlendirme sırası nedeniyle mükemmel bir çözüm OLMAYABİLİR. Örneğin, ben bir nesne olup olmadığını kontrol ediyorum eğer nil, bunun dışında şu kod parçacığı bakmak bir malı hangi edecek panichalindemyObj equals nil

type MyStruct struct {
   field1 string
   field2 string 
}

var myObj *MyStruct
myObj = nil 

myField := map[bool]string{true: myObj.field1, false: "empty!"}[myObj != nil}

Çünkü durumu değerlendirmeden önce harita oluşturulacak ve inşa myObj = niledilecek , bu yüzden böyle bir durumda panik yapacaktır.

Yine de koşulları tek bir basit satırda yapabileceğinizi belirtmeyi unutmayın, aşağıdakileri kontrol edin:

var c int
...
if a > b { c = a } else { c = b}

4

Üçlü operatör yerine lambda işlevini kullanın

örnek 1

maksimum int vermek

package main

func main() {

    println( func(a,b int) int {if a>b {return a} else {return b} }(1,2) )
}

Örnek 2

Diyelim ki must(err error)hataları işlemek için bu işleve sahip olduğunuzu ve bir koşul yerine getirilmediğinde onu kullanmak istediğinizi varsayalım . ( https://play.golang.com/p/COXyo0qIslP adresinde keyfini çıkarın )

package main

import (
    "errors"
    "log"
    "os"
)

// must is a little helper to handle errors. If passed error != nil, it simply panics.
func must(err error) {
    if err != nil {
        log.Println(err)
        panic(err)
    }
}

func main() {

    tmpDir := os.TempDir()
    // Make sure os.TempDir didn't return empty string
    // reusing my favourite `must` helper
    // Isn't that kinda creepy now though?
    must(func() error {
        var err error
        if len(tmpDir) > 0 {
            err = nil
        } else {
            err = errors.New("os.TempDir is empty")
        }
        return err
    }()) // Don't forget that empty parentheses to invoke the lambda.
    println("We happy with", tmpDir)
}

2
ilginç yaklaşım, daha karmaşık durumlarda faydalı olabilir. :)
thoroc

1

Bazen, tanımlama ve atamanın aynı satırda gerçekleşmesini sağlamak için anonim işlevi kullanmaya çalışıyorum. aşağıdaki gibi:

a, b = 4, 8

c := func() int {
    if a >b {
      return a
    } 
    return b
  } ()

https://play.golang.org/p/rMjqytMYeQ0


0

Dilde çok benzer bir yapı mevcut

**if <statement>; <evaluation> {
   [statements ...]
} else {
   [statements ...]
}*

*

yani

if path,err := os.Executable(); err != nil {
   log.Println(err)
} else {
   log.Println(path)
}

0

Bunun için bir kapatma kullanabilirsiniz:

func doif(b bool, f1, f2 func()) {
    switch{
    case b:
        f1()
    case !b:   
        f2()
    }
}

func dothis() { fmt.Println("Condition is true") }

func dothat() { fmt.Println("Condition is false") }

func main () {
    condition := true
    doif(condition, func() { dothis() }, func() { dothat() })
}

Go'daki kapanış sözdizimiyle ilgili tek yakınmam, varsayılan sıfır parametresi sıfır dönüş işlevi için bir takma ad olmamasıdır, o zaman çok daha güzel olurdu (haritayı, diziyi ve dilim değişmezlerini sadece bir tür adıyla nasıl bildireceğinizi düşünün).

Ya da bir yorumcunun önerdiği gibi daha kısa versiyonu:

func doif(b bool, f1, f2 func()) {
    switch{
    case b:
        f1()
    case !b:   
        f2()
    }
}

func dothis() { fmt.Println("Condition is true") }

func dothat() { fmt.Println("Condition is false") }

func main () {
    condition := true
    doif(condition, dothis, dothat)
}

İşlevlere parametreler vermeniz gerekirse yine de bir kapatma kullanmanız gerekir. Bu, parametrelerin yöntemlerle ilişkili yapı olduğu düşündüğüm işlevlerden ziyade yöntemlerin geçişi durumunda önlenebilir.


Daha kısa versiyondoif(condition, dothis, dothat)
vellotis

1
Evet, sadece işlevleri geçerek bu daha da kısa olacaktır. Birinin bu işleve yalnızca bir yardımcı program kitaplığında bir kez sahip olması gerekir ve hepsini kodunuz aracılığıyla kullanabilirsiniz.
Louki Sumirniy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.