如何优雅地检查三个值的相等性?

时间:2016-06-17 14:29:23

标签: go syntax equality readability convention

说我有值[root@localhost ml-100k]# ls -l /opt/hadoop/weekday_mapper.py -rwxr--r--. 1 root root 278 Jun 17 10:10 /opt/hadoop/weekday_mapper.py ab。我想知道他们是否平等。如果我做

c

然后我收到编译错误

if a == b == c{...}

这很明显,因为这解析为:

invalid operation: a == b == c (mismatched types bool and TypeOfABandC)

(a == b) == c 是一个布尔。

我当然能做到:

(a == b)

然而,这看起来并不好看,让人感到困惑。还有另一种方式吗?

1 个答案:

答案 0 :(得分:17)

事先说明:

您最后提出的解决方案最短,最清晰,最有效的方法来比较3个值是否相等:

if a == b && a == c {
    fmt.Println("Clearest: all 3 are equal")
}

或者(根据自己的喜好):

if a == b && b == c {
    fmt.Println("Clearest: all 3 are equal")
}

这个答案的其余部分(后面的内容)只是用语言规范和语言的能力来表达,展示我觉得有趣和有创意的东西。他们并不试图提供卓越的解决方案。

Go Playground上尝试以下所有示例。这些示例建立在Spec: Comparison operators

中定义的比较的术语和结果之上

一般说明:在下面的示例中,我使用了interface{}类型,它将适用于您的值所具有的任何类型(abc),但如果您使用例如,他们知道它们属于int类型,您也可以使用该特定类型(这将提高效率并缩短示例的长度)。

map作为一组

if len(map[interface{}]int{a: 0, b: 0, c: 0}) == 1 {
    fmt.Println("Map set: all 3 are equal")
}

有效地,我们将所有可比较的值放入map作为键,如果全部相等,则地图中只有1对,因此地图的“长度”将为1.值类型地图在这里没有任何作用,它可以是任何东西。我使用了int,因为这会产生最短的composite literal(定义{{​​1}}值)。

此解决方案非常灵活,因为您可以使用任意数量的值来测试所有值是否相等,而不仅仅是3。

使用数组

阵列具有可比性(与切片不同):

map

如果if [2]interface{}{a, b} == [2]interface{}{b, c} { fmt.Println("Arrays: all 3 are equal") } true(如果相应的元素相等),则数组比较结果为a == b

请注意,您也可以对任意数量的值应用此方法。对于5个值,它看起来像这样:

b == c

有一个棘手的if [4]interface{}{a, b, c, d} == [4]interface{}{b, c, d, e} { fmt.Println("Arrays: all 5 are equal") }

map

此复合文字会将if map[interface{}]bool{a: b == c}[b] { fmt.Println("Tricky map: all 3 are equal") } 的比较结果指定给键b == c。我们询问与密钥a关联的值。如果b,索引表达式的结果将是a == b的结果,即是否所有3个值都相等。如果b == c,那么值类型的零值将是结果,a != b的情况为false,正确地告知所有3个值都不相等。

使用匿名bool s

struct值也具有可比性,因此:

struct

使用(命名)if struct{ a, b interface{} }{a, b} == struct{ a, b interface{} }{b, c} { fmt.Println("Anon structs: all 3 are equal") } s

如果我们事先定义一个简单的struct

struct

比较将更加紧凑:

type P struct{ a, b interface{} }

(注意if (P{a, b} == P{b, c}) { fmt.Println("Structs: all 3 are equal") } 语句的表达式必须放在括号中以避免parsing ambiguity - 否则它是编译时错误!)

使用切片

切片无法比较,因此我们需要借用reflect.DeepEqual()的一些帮助:

if

使用帮助函数

if reflect.DeepEqual([]interface{}{a, b}, []interface{}{b, c}) {
    fmt.Println("Slices: all 3 are equal")
}

使用它:

func AllEquals(v ...interface{}) bool {
    if len(v) > 1 {
        a := v[0]
        for _, s := range v {
            if a != s {
                return false
            }
        }
    }
    return true
}

此解决方案也很灵活,您可以使用任意数量的值调用if AllEquals(a, b, c) { fmt.Println("Helper function: all 3 are equal") }

请注意,如果我们还愿意在此处致电AllEquals(),我们可以使AllEquals()功能更加紧凑:

reflect.DeepEqual()
相关问题