如果另有声明,如何做一线?


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没有一个。
西蒙·怀特海德2014年

6
我相信您要查找的单词是“三元”
BenjaminRH


10
需要澄清的是,三元运算符是arity 3的任何运算符,即绑定3个子表达式的任何运算符。C碰巧只有一个这样的运算符。这就是为什么通常将其称为三元运算符。它的真实名称是“条件运算符”。
2014年

Answers:


131

正如评论所提到的,Go不支持三元一线。我能想到的最短形式是:

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

但是请不要这样做,这是不值得的,只会使阅读您代码的人感到困惑。


83
@thoroc实际上我可能会避免这种情况,因为它不是直观的恕我直言,不值得保存两行来降低可读性。
Not_a_Golfer

14
@thoroc,请听听Not_a_Golfer所说的。您应该努力编写可维护的软件,而不是炫耀自己。整洁的技巧很整洁,但是下一个阅读您的代码的人(包括您在几个月/几年内的代码)不会感激它们。
kostix

3
就可读性而言,这取决于。我认为这更具可读性,但是像其他任何东西一样,它可能会被滥用。如果需要在if块之外声明不需要的变量,那么我认为这是一个胜利者。
arjabbar 2015年

@Not_a_Golfer不仅是对称可读性,而且与意图的结构对比也在编译后的代码中,有时甚至会为冗余初始化付出额外的代价。

5
哦,高兴,看看没有三元运算符可以得到多少Go。除了所作的可读性注释之外,您还更改了一个惰性评估的构造,其中仅运行了一个分支,而一个分支始终在其中运行,而第二个分支也可能在运行。
itsbruce

29

我经常使用以下内容:

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

基本上与@Not_a_Golfer相同,但使用类型推断


4
缺点相同:将非对称解决方案用于明显对称的需求时,您的理解会变得复杂。

2
同样的缺点是应该将原来应该是惰性评估的构造转换为只能使用两个分支中的一个分支,而总是要对其进行评估的分支,有时会同时使用两个分支(在这种情况下,第一个评估是多余的)
导致

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常见问题解答(duh),并明确指出,该语言不可用:

Go是否有?:运算符?

Go中没有三元形式。您可以使用以下方法获得相同的结果:

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

发现可能对此主题感兴趣的其他信息:


它也可以在同一行:var c int; if a > b { c = a } else { c = b }?但我建议将其保留在5行中,以形成一个供读者娱乐的灯箱;)
Wolf

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

使用lambda函数代替三元运算符

例子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


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中的闭包语法唯一的抱怨是默认零参数零返回函数没有别名,这会好得多(想想如何只用类型名声明map,array和slice文字)。

甚至是较短的版本,如评论员所建议的那样:

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

1
是的,只传递函数就更短了。一个人只需在一个实用程序库中拥有一次此功能,就可以在代码中全部使用它。
路基·苏米尔尼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.