在C/ c++(以及该家族的许多语言)中,根据条件声明和初始化变量的常用习语使用三元条件操作符:

int index = val > 0 ? val : -val

Go没有条件运算符。实现上面同一段代码的最惯用的方法是什么?我想出了下面的解决方案,但它似乎相当啰嗦

var index int

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

还有更好的办法吗?


当前回答

虽然被创作者所回避,但俏皮话也有自己的一席之地。

这个函数解决了惰性求值的问题,它允许你在必要时可选地传递函数来求值:

func FullTernary(e bool, a, b interface{}) interface{} {
    if e {
        if reflect.TypeOf(a).Kind() == reflect.Func {
            return a.(func() interface{})()
        }
        return a
    }
    if reflect.TypeOf(b).Kind() == reflect.Func {
        return b.(func() interface{})()
    }
    return b
}

func demo() {
    a := "hello"
    b := func() interface{} { return a + " world" }
    c := func() interface{} { return func() string { return "bye" } }
    fmt.Println(FullTernary(true, a, b).(string)) // cast shown, but not required
    fmt.Println(FullTernary(false, a, b))
    fmt.Println(FullTernary(true, b, a))
    fmt.Println(FullTernary(false, b, a))
    fmt.Println(FullTernary(true, c, nil).(func() string)())
}

输出

hello
hello world
hello world
hello
bye

传入的函数必须返回一个接口{}以满足内部强制转换操作。 根据上下文,您可以选择将输出强制转换为特定类型。 如果你想从这个函数中返回一个函数,你需要用c来包装它。


这里的独立解决方案也很好,但对于某些用途可能不太清楚。

其他回答

No Go没有三元运算符。使用if/else语法是惯用的方法。

Why does Go not have the ?: operator? There is no ternary testing operation in Go. You may use the following to achieve the same result: if expr { n = trueVal } else { n = falseVal } The reason ?: is absent from Go is that the language's designers had seen the operation used too often to create impenetrably complex expressions. The if-else form, although longer, is unquestionably clearer. A language needs only one conditional control flow construct. — Frequently Asked Questions (FAQ) - The Go Programming Language

没有括号,map三元很容易读:

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

这不会比if/else更好,需要施放但有效。仅供参考:

基准基准三元-8 100000000 18.8 ns/op

BenchmarkAbsIfElse-8 2000000000 0.27 ns/op

关于三元运算符的惯用方法,还有一个建议:

package main

import (
    "fmt"
)

func main() {
    val := -5

    index := func (test bool, n, d int) int {
        if test {
            return n
        }
        return d
    }(val > 0, val, -val)
    
    fmt.Println(index)
}

去操场

如果你所有的分支都产生了副作用,或者计算成本很高,下面是一个语义保留的重构:

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

通常没有开销(内联),最重要的是,不会因为只使用一次的辅助函数而使名称空间混乱(这会影响可读性和维护)。生活的例子

注意,如果你天真地应用Gustavo的方法:

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

你会得到一个有着不同行为的程序;在val <= 0的情况下,程序将输出一个非正值,而它不应该!(类似地,如果反转分支,就会不必要地调用缓慢的函数,从而引入开销。)