简体   繁体   English

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

[英]How do I check the equality of three values elegantly?

Say I have values a , b and c . 说我有值abc I want to find out if they are equal. 我想知道他们是否平等。 If I do 如果我做

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

Then I get a compile error 然后我得到一个编译错误

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

This is pretty obvious, because this parses to: 这很明显,因为这解析为:

(a == b) == c

And (a == b) is a bool. 并且(a == b)是一个布尔。

Of course I can do: 我当然可以这样做:

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

However, this isn't very nice looking and feels confusing. 然而,这看起来并不是很好看并且让人感到困惑。 Is there another way? 还有另外一种方法吗?

A note beforehand: 事先说明:

Your last proposed solution is the shortest, clearest and most efficient way to compare if 3 values are equal: 如果3个值相等,您最后提出的解决方案最短,最清晰,最有效的比较方法:

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

or alternatively (to your liking): 或者(根据自己的喜好):

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

The rest of this answer (what follows) is just toying with the language specification and the language's capabilities, presenting what I find fun and creative. 这个答案的其余部分(后面的内容)只是用语言规范和语言的能力来表达,展示我觉得有趣和有创意的东西。 They do not attempt to provide a superior solution. 他们并不试图提供卓越的解决方案。


Try all the examples below on the Go Playground . Go Playground上尝试以下所有示例。 The examples build on the terms and the result of the comparisons which are defined in Spec: Comparison operators . 这些示例建立在Spec:Comparison运算符中定义的比较的术语和结果之上。

General note: in the examples below I used the type interface{} which will work whatever type your values have ( a , b and c ), but if you know they are of type int for example, you can use that specific type too (which would improve efficiency and shorten the length of the examples). 一般说明:在下面的示例中,我使用了类型interface{} ,它将适用于您的值具有的任何类型( abc ),但是如果您知道它们的类型为int ,那么您也可以使用该特定类型(这将提高效率并缩短例子的长度)。

With a map as a set map作为一组

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

Effectively we put all comparable values into a map as keys, and if all are equal, there will be only 1 pair in the map, so the "length" of the map will be 1. The value type of the map doesn't play any role here, it could be anything. 实际上,我们将所有可比较的值作为键放入map中,如果全部相等,则地图中只有1对,因此地图的“长度”将为1.地图的值类型不会播放在这里任何角色,都可以是任何东西。 I used int because this results in the shortest composite literal (that defines the map value). 我使用int因为这导致最短的复合文字 (定义map值)。

This solution is flexible as you can use any number of values to test if all are equal, not just 3. 此解决方案非常灵活,因为您可以使用任意数量的值来测试所有值是否相等,而不仅仅是3。

With arrays 有阵列

Arrays are comparable (unlike slices): 阵列具有可比性(与切片不同):

if [2]interface{}{a, b} == [2]interface{}{b, c} {
    fmt.Println("Arrays: all 3 are equal")
}

The result of the array comparison will be true if a == b and b == c (if the corresponding elements are equal). 如果a == bb == c (如果相应的元素相等),则数组比较的结果将为true

Note that you can apply this method on any number of values as well. 请注意,您也可以对任意数量的值应用此方法。 It would look like this for 5 values: 对于5个值,它看起来像这样:

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

With a tricky map 有一个棘手的map

if map[interface{}]bool{a: b == c}[b] {
    fmt.Println("Tricky map: all 3 are equal")
}

This composite literal will assign the comparision result of b == c to the key a . 该复合文字将b == c的比较结果分配给键a And we ask the value associated with the key b . 我们询问与密钥b相关的值。 If a == b , the result of the indexing expression will be the result of b == c , that is, whether all 3 values are equal. 如果a == b ,索引表达式的结果将是b == c的结果,即是否所有3个值都相等。 If a != b , then the zero value of the value type will be the result, which is false in case of bool , properly telling that all 3 values are not equal. 如果a != b ,那么值类型的零值将是结果,在bool情况下为false ,正确地告知所有3个值都不相等。

With anonymous struct s 使用匿名struct

struct values are also comparable, so: struct值也具有可比性,因此:

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

With (named) struct s 使用(命名) struct s

If we define a simple struct beforehand: 如果我们事先定义一个简单的struct

type P struct{ a, b interface{} }

Comparison will be much more compact: 比较将更加紧凑:

if (P{a, b} == P{b, c}) {
    fmt.Println("Structs: all 3 are equal")
}

(Note that the expression of the if statement must be put in parenthesis to avoid parsing ambiguity - else it's a compile time error!) (注意, if语句的表达式必须放在括号中以避免解析歧义 - 否则它是编译时错误!)

With slices 用切片

Slices are not comparable, so we will need to borrow some help from reflect.DeepEqual() : 切片不具有可比性,因此我们需要借一些来自reflect.DeepEqual()帮助:

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

With a helper function 具有辅助功能

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

And using it: 并使用它:

if AllEquals(a, b, c) {
    fmt.Println("Helper function: all 3 are equal")
}

This solution is also flexible, you can call AllEquals() with any number of values. 此解决方案也很灵活,您可以使用任意数量的值调用AllEquals()

Note that we can make the AllEquals() function more compact if we're also willing to call reflect.DeepEqual() here: 请注意,如果我们还愿意在这里调用reflect.DeepEqual() ,我们可以使AllEquals()函数更紧凑:

func AllEquals2(v ...interface{}) bool {
    if len(v) < 2 {
        return true
    }
    return reflect.DeepEqual(v[:len(v)-1], v[1:])
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM