한 줄짜리 if else 문을 수행하는 방법은 무엇입니까?


104

PHP에서하는 것처럼 go (golang)에서 변수 할당을 사용하여 간단한 if-else 문을 작성할 수 있습니까? 예를 들면 :

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

현재 다음을 사용해야합니다.

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

이 제어문이 이름을 기억할 수없고 사이트 내 또는 Google 검색을 통해 정보를 찾을 수없는 경우 죄송합니다. : /


4
삼항 연산자라고합니다. 그리고 아니요, Go에는 없습니다.
Simon Whitehead

6
나는 당신이 찾고있는 단어가 "원"이라고 생각
BenjaminRH


10
명확히하기 위해 삼항 연산자는 arity 3의 모든 연산자, 즉 3 개의 하위 표현식을 바인딩하는 모든 연산자입니다. C는 그러한 연산자를 하나만 가지고 있습니다. 이것이 일반적으로 삼항 연산자라고 불리는 이유입니다. 하지만 실제 이름은 "조건부 연산자"입니다.
thwd

답변:


132

언급했듯이 Go는 삼진 1 라이너를 지원하지 않습니다. 내가 생각할 수있는 가장 짧은 형식은 다음과 같습니다.

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

하지만 그렇게하지 마십시오. 그럴 가치가 없으며 코드를 읽는 사람들을 혼란스럽게 할뿐입니다.


83
@thoroc 나는 직관적이지 않은 IMHO이기 때문에 실제로는 그것을 피할 것입니다. 가독성을 위해 2 줄을 절약 할 가치가 없습니다.
Not_a_Golfer 2014 년

14
@thoroc, Not_a_Golfer가 말한 것을 들어주세요. 자신을 과시 하지 말고 유지 보수 가능한 소프트웨어를 작성하려고 노력해야합니다 . 깔끔한 트릭은 깔끔하지만 다음 사람 (몇 달 / 년 안에 당신을 포함)은 당신의 코드를 읽지 않을 것입니다.
kostix 2014 년

3
가독성에 따라 다릅니다. 나는 이것이 더 읽기 쉽다고 생각하지만 다른 것과 마찬가지로 남용 될 수 있습니다. if 블록 밖에서 필요하지 않은 변수를 선언해야한다면 이것이 승자라고 생각합니다.
arjabbar 2015 년

@Not_a_Golfer 그것은 대칭에 의한 가독성 일뿐만 아니라 의도와의 구조적 대조는 컴파일 된 코드에도 있으며 때로는 중복 초기화에 대한 추가 비용이 있습니다.
늑대

5
오, 기쁨, 삼항 연산자가 없어서 Go가 얼마나 많이 얻었는지보세요. 가독성 주석을 작성하는 것 외에도 하나의 분기 만 실행되는 경우 첫 번째 분기가 항상 실행되고 두 번째 분기가 추가로 실행될 수있는 분기로 실행되는 지연 평가 구조를 변경했습니다.
itsbruce

29

나는 종종 다음을 사용합니다.

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

기본적으로 @Not_a_Golfer와 동일하지만 유형 추론을 사용 합니다 .


4
동일한 단점이 있습니다. 명백한 대칭 요구 사항에 대해 비대칭 솔루션을 사용할 때 이해가 복잡해집니다.
늑대

2
그리고 무엇을 돌려 같은 단점은 때때로 모두 (이 경우 최초의 평가였다 중복) 하나는 항상 평가됩니다 두 가지 중 하나만 어느 하나에 사용됩니다 게으르게 - 평가 구조이어야한다
itsbruce

1
사용 사례에 따라 이것은 여전히 ​​매우 유용 할 수 있습니다. 예 : listeningPath := "production.some.com"; if DEBUG { listeningPath := "development.some.com" }생산을위한 삼진법과 같은 속도, 그리고 꽤 좋은 가독성.
Levite

나는 의도적으로 CPU 사이클을 낭비 할 때 보통 울습니다.
alessiosavi

28

다른 사람들이 언급 Go했듯이은 삼항 원 라이너를 지원하지 않습니다. 그러나 원하는 것을 달성하는 데 도움이되는 유틸리티 함수를 작성했습니다.

// 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
}

다음은 사용 방법을 보여주는 몇 가지 테스트 사례입니다.

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)
}

재미를 위해 다음과 같은 더 유용한 유틸리티 함수를 작성했습니다.

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

이들 중 하나를 사용하려면 https://github.com/shomali11/util에서 찾을 수 있습니다.


12

정답을 알려 주셔서 감사합니다.

방금 Golang FAQ (duh)를 확인 했는데 다음과 같이 해당 언어로 제공되지 않는다고 분명히 명시되어 있습니다.

Go에? : 연산자가 있습니까?

Go에는 삼항 형식이 없습니다. 다음을 사용하여 동일한 결과를 얻을 수 있습니다.

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

주제에 관심이있을 수있는 추가 정보 :


한 줄로도 가능합니다. var c int; if a > b { c = a } else { c = b }? 하지만 독자의 휴양을위한 가벼운 블록을 형성하는 5 개 라인을 유지하는 게 좋을 것)
늑대

7

한 가지 가능한 방법이 있는지 제가 확인하고지도, 간단한 사용하여 하나 개의 라인에서이 작업을 수행하려면 a > b이 경우 true내가 할당하고 ca, 그렇지 않은b

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

그러나 이것은 놀랍게 보이지만 경우에 따라 평가 순서 때문에 완벽한 솔루션이 아닐 수도 있습니다. 예를 들어, 나는 객체가되어 있는지 여부를 확인하고 경우에 nil, 그것의 다음 코드에서 모습을 몇 가지 속성을 얻을 수있는 것이다 panic의 경우myObj 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}

조건을 평가하기 전에 맵이 먼저 생성되고 빌드 myObj = nil되므로이 경우 단순히 패닉 상태가됩니다.

한 줄로만 조건을 수행 할 수 있다는 점을 잊지 말고 다음을 확인하십시오.

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

4

삼항 연산자 대신 람다 함수 사용

예 1

최대 정수를 제공하기 위해

package main

func main() {

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

예 2

must(err error)오류를 처리하기 위해이 함수가 있고 조건이 충족되지 않을 때 사용하려고 한다고 가정합니다 . ( https://play.golang.com/p/COXyo0qIslP 에서 즐기세요 )

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
흥미로운 접근 방식은 더 복잡한 경우에 유용 할 수 있습니다. :)
thoroc

1

때로는 익명 함수를 사용하여 동일한 줄에서 정의 및 할당을 수행하려고합니다. 아래와 같이 :

a, b = 4, 8

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

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


0

매우 유사한 구조가 언어로 제공됩니다.

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

*

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

0

이를 위해 클로저를 사용할 수 있습니다.

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의 클로저 구문에 대한 유일한 불만은 기본 0 매개 변수 0 반환 함수에 대한 별칭이 없다는 것입니다.

또는 댓글 작성자가 제안한 짧은 버전도 있습니다.

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)
}

함수에 매개 변수를 제공해야하는 경우 여전히 클로저를 사용해야합니다. 이것은 매개 변수가 메소드와 연관된 구조체 인 내가 생각하는 함수가 아닌 메소드를 전달하는 경우에 피할 수 있습니다.


더 짧은 버전doif(condition, dothis, dothat)
vellotis 2018

1
예, 훨씬 더 짧아서 함수 만 전달합니다. 이 함수는 하나의 유틸리티 라이브러리에 한 번만 있으면 코드를 통해 모두 사용할 수 있습니다.
Louki Sumirniy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.