[go] C의 삼항 연산자와 동등한 관용어는 무엇입니까?

C / C ++ (및 그 계열의 여러 언어)에서 조건에 따라 변수를 선언하고 초기화하는 일반적인 관용구는 삼항 조건 연산자를 사용합니다.

int index = val > 0 ? val : -val

Go에는 조건부 연산자가 없습니다. 위와 동일한 코드를 구현하는 가장 관용적 인 방법은 무엇입니까? 나는 다음 해결책에 왔지만 꽤 장황한 것처럼 보인다.

var index int

if val > 0 {
    index = val
} else {
    index = -val
}

더 좋은 것이 있습니까?



답변

지적했듯이 (그리고 놀랍지 않게도) 사용하는 if+else것은 실제로 Go에서 조건부를 수행 하는 관용적 방법 입니다.

그러나 완전한 var+if+else코드 블록 외에도이 철자가 자주 사용됩니다.

index := val
if val <= 0 {
    index = -val
}

및와 같이 반복 가능한 코드 블록이 있으면이 int value = a <= b ? a : b를 보유하는 함수를 만들 수 있습니다.

func min(a, b int) int {
    if a <= b {
        return a
    }
    return b
}

...

value := min(a, b)

컴파일러는 이러한 간단한 함수를 인라인하므로 빠르고 명확하며 짧습니다.


답변

No Go에는 if / else 구문 을 사용 하는 관용적 인 삼항 연산자가 없습니다 .

Go에? : 연산자가없는 이유는 무엇입니까?

Go에는 3 진 테스트 작업이 없습니다. 다음을 사용하여 동일한 결과를 얻을 수 있습니다.

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

?:Go에 빠진 이유 는 언어 디자이너가 조작이 너무 자주 사용되어 복잡한 표현을 만들지 못했기 때문입니다. if-else형태는 이상하지만, 의심 할 여지없이 명확하다. 언어에는 조건부 제어 흐름 구성이 하나만 필요합니다.

— 자주 묻는 질문 (FAQ)-Go 프로그래밍 언어


답변

다음과 같은 삼항식이 있다고 가정합니다 (C).

int a = test ? 1 : 2;

Go의 관용적 접근 방식은 단순히 if블록을 사용하는 것입니다 .

var a int

if test {
  a = 1
} else {
  a = 2
}

그러나 이는 요구 사항에 맞지 않을 수 있습니다. 필자의 경우 코드 생성 템플릿에 인라인식이 필요했습니다.

즉시 평가 된 익명 함수를 사용했습니다.

a := func() int { if test { return 1 } else { return 2 } }()

이렇게하면 두 가지 모두 평가되지 않습니다.


답변

지도 삼항은 괄호없이 읽기 쉽습니다.

c := map[bool]int{true: 1, false: 0} [5 > 4]


답변

func Ternary(statement bool, a, b interface{}) interface{} {
    if statement {
        return a
    }
    return b
}

func Abs(n int) int {
    return Ternary(n >= 0, n, -n).(int)
}

그렇지 않으면 캐스팅보다 성능이 뛰어나지 않지만 작동합니다. 참고 사항 :

벤치 마크 : AbsTernary-8 100000000 18.8 ns / op

BenchmarkAbsIfElse-8 2000000000 0.27 ns / op


답변

경우 모든 당신의 가지 부작용을 만들 거나있는 많은 계산 다음은을 것이다 의미 보존 리팩토링 :

index := func() int {
    if val > 0 {
        return printPositiveAndReturn(val)
    } else {
        return slowlyReturn(-val)  // or slowlyNegate(val)
    }
}();  # exactly one branch will be evaluated

일반적으로 오버 헤드 (인라인 된)가 없으며 가장 중요 하게는 한 번만 사용되는 도우미 함수로 네임 스페이스를 어지럽히 지 않고 (가독성 및 유지 관리를 방해합니다). 라이브 예

구스타보의 접근 방식 을 순진하게 적용한다면 같습니다.

    index := printPositiveAndReturn(val);
    if val <= 0 {
        index = slowlyReturn(-val);  // or slowlyNegate(val)
    }

당신은 다른 행동을 가진 프로그램을 얻게 될 것입니다 ; val <= 0프로그램이 양수가 아닌 값을 인쇄하는 경우에는 그렇지 않습니다! (분명히 분기를 반전하면 불필요하게 느린 함수를 호출하여 오버 헤드가 발생합니다.)


답변

서문 : 주장하지 않고if else 갈 길이 , 우리는 여전히 언어 기반 구조를 가지고 놀고 즐거움을 찾을 수 있습니다.

다음 If구성은 github.com/icza/gox라이브러리에서 다른 많은 방법으로 사용할 수 있으며 builtinx.If유형입니다.


Go 는와 같은 기본 유형을 포함 하여 모든 사용자 정의 유형 에 메소드를 첨부 할 수 있습니다 bool. 기본 유형bool 으로 사용자 정의 유형을 작성한 다음 조건에 대한 간단한 유형 변환 으로 메소드에 액세스 할 수 있습니다. 피연산자를 받고 선택하는 메소드입니다.

이 같은:

type If bool

func (c If) Int(a, b int) int {
    if c {
        return a
    }
    return b
}

어떻게 사용할 수 있습니까?

i := If(condition).Int(val1, val2)  // Short variable declaration, i is of type int
     |-----------|  \
   type conversion   \---method call

예를 들어 삼항 max():

i := If(a > b).Int(a, b)

삼항 abs():

i := If(a >= 0).Int(a, -a)

멋있고, 단순하고 우아하며 효율적입니다 ( 인라인 에도 적합 함) ).

“실제”삼항 연산자와 비교할 때 한 가지 단점 : 항상 모든 피연산자를 평가합니다.

지연되고 필요한 경우에만 평가를 수행하려면 필요한 경우 / 필요할 때만 호출되는 함수 ( 선언 된 함수 또는 메소드 또는 함수 리터럴 ) 를 사용하는 것이 유일한 옵션입니다 .

func (c If) Fint(fa, fb func() int) int {
    if c {
        return fa()
    }
    return fb()
}

그것을 사용 :하자의 우리가 계산에 이러한 기능이 가정 ab:

func calca() int { return 3 }
func calcb() int { return 4 }

그때:

i := If(someCondition).Fint(calca, calcb)

예를 들어, 현재 연도> 2020 인 조건 :

i := If(time.Now().Year() > 2020).Fint(calca, calcb)

함수 리터럴을 사용하려는 경우 :

i := If(time.Now().Year() > 2020).Fint(
    func() int { return 3 },
    func() int { return 4 },
)

마지막 참고 사항 : 서명이 다른 기능이있는 경우 여기서 사용할 수 없습니다. 이 경우 서명이 일치하는 함수 리터럴을 사용하여 여전히 적용 할 수 있습니다.

예를 들어 calca()calcb()매개 변수가있는 경우 (반환 값 외에) :

func calca2(x int) int { return 3 }
func calcb2(x int) int { return 4 }

이것은 당신이 그들을 사용할 수있는 방법입니다 :

i := If(time.Now().Year() > 2020).Fint(
    func() int { return calca2(0) },
    func() int { return calcb2(0) },
)

Go Playground 에서이 예제를 사용해보십시오 .