我如何优雅地检查三个值的相等性? [英] How do I check the equality of three values elegantly?

查看:238
本文介绍了我如何优雅地检查三个值的相等性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我的值 a b c 。我想知道他们是否平等。如果我做的话

 如果a == b == c {...} 

然后我得到一个编译错误

 无效操作:a == b == c(不匹配类型bool和TypeOfABandC)

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

 (a == b)== c 

(a == b)是一个bool。



当然我可以这样做:

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

然而,这看起来不太好看,感觉混乱。有没有另外一种方法?

解决方案

预先记录

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

  if a == b&& a == c {
fmt.Println(最清晰:所有3都相等)
}

或者(根据你的喜好):

  if a == b&& b == c {
fmt.Println(最清楚:所有3都相等)
}

这个答案的其余部分(接下来的内容)就是关于语言规范和语言的能力,展示我觉得有趣和有创意的东西。他们不会试图提供更好的解决方案。






请尝试以下 Go Playground 。这些示例基于在规范:比较运算符中定义的比较条款和结果。



一般说明:在下面的例子中,我使用了界面{} 类型, ( a b c ),但是如果您知道它们的类型是 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 ,因为这会导致最短的复合文字(定义 map 值)。



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

有数组

):

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

如果 a == b ,数组比较的结果是 true b == c (如果相应的元素相等)。

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

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



使用棘手的 map



<$ p如果map [interface {}] bool {a:b == c} [b] {
fmt.Println(Tricky map:all 3 are equal)$ b $ b}

该复合文字将分配 b == c的比较结果 a 键。我们询问与 b 关联的值。如果 a == b ,索引表达式的结果将是 b == c 的结果,那就是,所有3个值是否相等。如果 a!= b ,那么值类型的零值将是结果,如果是 false bool ,正确地表明所有3个值不相等。



使用匿名 struct s



struct 值也是可比的,所以:

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



< h3>如果我们定义一个简单的 struct

code>事前:

  type P struct {a,b interface {}} 


$ b

比较将会更紧凑:

  if(P {a,b} == P {b,c}){
fmt.Println(Structs:all 3 are equal)
}
语句>的表达式必须放在括号内以避免解析歧义 - 否则这是一个编译时错误!)



切片



切片不具可比性,因此我们需要借助 reflect.DeepEqual()

 如果reflect.DeepEqual([] interface {} {a,b},[] interface {} {b,c}){
fmt.Println(片:所有3都相等)
}



借助辅助函数



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

使用它:

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

这个解决方案也很灵活,你可以调用 AllEquals()以及任意数量的值。



注意,我们可以使 AllEquals() reflect.DeepEqual()

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


Say I have values a, b and c. 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.

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:

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. The examples build on the terms and the result of the comparisons which are defined in Spec: Comparison operators.

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

With a map as a set

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. I used int because this results in the shortest composite literal (that defines the map value).

This solution is flexible as you can use any number of values to test if all are equal, not just 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).

Note that you can apply this method on any number of values as well. It would look like this for 5 values:

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

With a tricky 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. And we ask the value associated with the key 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. 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.

With anonymous structs

struct values are also comparable, so:

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

With (named) structs

If we define a simple struct beforehand:

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

With slices

Slices are not comparable, so we will need to borrow some help from 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.

Note that we can make the AllEquals() function more compact if we're also willing to call reflect.DeepEqual() here:

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

这篇关于我如何优雅地检查三个值的相等性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆