结构体的比较、接口的比较

观察下面的程序的输出结果

func main() {
    sn1 := struct {
        age  int
        name string
    }{age: 11, name: "qq"}
    
    sn2 := struct {
        age  int
        name string
    }{age: 11, name: "qq"}

    if sn1 == sn2 {
        fmt.Println("sn1 == sn2")
    }

    sm1 := struct {
        age int
        m   map[string]string
    }{age: 11, m: map[string]string{"a": "1"}}
    
    sm2 := struct {
        age int
        m   map[string]string
    }{age: 11, m: map[string]string{"a": "1"}}

    if sm1 == sm2 {
        fmt.Println("sm1 == sm2")
    }
}

参考答案及解析:编译不通过 invalid operation: sm1 == sm2

这道题目考的是结构体的比较,有几个需要注意的地方:

  1. 结构体只能比较是否相等,但是不能比较大小。
  2. 相同类型的结构体才能够进行比较结构体是否相同不但与属性类型有关,还与属性顺序相关,sn3 与 sn1 就是不同的结构体;
sn3:= struct {
 name string
 age  int
}{age:11,name:"qq"}

 

如果 struct 的所有成员都可以比较,则该 struct 就可以通过 == 或 != 进行比较是否相等,比较时逐个项进行比较,如果每一项都相等,则两个结构体才相等,否则不相等。

 

那什么是可比较的呢?

常见的有 bool、数值型、字符、指针、数组等,像切片、map、函数等是不能比较的

 

关于各种数据类型的比较,go语言给出了详细的描述(http://docs.studygolang.com/ref/spec#Comparison_operators)

如下摘录了一部分

Comparison operators

Comparison operators compare two operands and yield an untyped boolean value.

== equal != not equal < less <= less or equal > greater >= greater or equal

In any comparison, the first operand must be assignable to the type of the second operand, or vice versa.

The equality operators == and != apply to operands that are comparable. The ordering operators <, <=, >, and >= apply to operands that are ordered. These terms and the result of the comparisons are defined as follows:

  • Boolean values are comparable. Two boolean values are equal if they are either both true or both false. 布尔值是可比较的。若两个布尔值均为false或true,则它们的相同的。
  • Integer values are comparable and ordered, in the usual way. 整形值是可比较的,而且可排序的。
  • Floating-point values are comparable and ordered, as defined by the IEEE-754 standard.浮点型值是可比较的和可排序的,正如 IEEE-754 中定义的那样。
  • Complex values are comparable. Two complex values u and v are equal if both real(u) == real(v) and imag(u) == imag(v).复数类型可比较的,对于复数类型u和v,若h real(u) == real(v) 和imag(u) == imag(v).,则它们相等的。
  • String values are comparable and ordered, lexically byte-wise.字符串值可比较和可排序,按词法按字节排序
  • Pointer values are comparable. Two pointer values are equal if they point to the same variable or if both have value nil. Pointers to distinct zero-size variables may or may not be equal.指针值是可比较的。如果两个指针指向相同的变量或两者均为nil,则两个指针值相同的;指向不同的零大小变量的指针可能相等,也可能不相等
  • Channel values are comparable. Two channel values are equal if they were created by the same call to make or if both have value nil.管道值是可比较的。若两个管道通过相同的make方式创建或者均为nil,则两个是可比较的。
  • Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.接口值是可比较的。若两个接口具有相同的动态类型,而且动态值也相同,或它们均为nil时,则这两个接口值是相同的。
  • A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t's dynamic type is identical to X and t's dynamic value is equal to x.对于非接口类型X的值x和接口类型T的值t,当类型X是可比较的,且X实现了T,则它们是可比较的。当t的动态类型是X,且t的动态类型值等于x时,它们相等。
  • Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.对于结构体而言,若它们的属性是可比较的,则它就是可比较的。当两个结构体值的非空白字段是相等的是,则两个结构体相等。
  • Array values are comparable if values of the array element type are comparable. Two array values are equal if their corresponding elements are equal.若数组元素类型的值是可比较的,则数组是可比较的。当两个数组中的相应位置上的元素相同时,则两个数组相等。

A comparison of two interface values with identical dynamic types causes a run-time panic if values of that type are not comparable. This behavior applies not only to direct interface value comparisons but also when comparing arrays of interface values or structs with interface-valued fields.

两个接口比较时,如果它们的动态类型相同,但是动态值是不可比较的,则会发生panic异常。这种行为不仅适用于直接的接口值比较,还适用于比较接口值或结构与接口值字段的数组

Slice, map, and function values are not comparable. However, as a special case, a slice, map, or function value may be compared to the predeclared identifier nil. Comparison of pointer, channel, and interface values to nil is also allowed and follows from the general rules above.

切片、map和func值不可比较的。然而,作为特例,slice、map或func值是能够和预定义的标示符nil比较的。将指针、通道和接口值与nil进行比较也是允许的,并且并遵循上面的一般规则。

const c = 3 < 4            // c is the untyped boolean constant true

type MyBool bool
var x, y int
var (
	// The result of a comparison is an untyped boolean.
	// The usual assignment rules apply.
	b3        = x == y // b3 has type bool
	b4 bool   = x == y // b4 has type bool
	b5 MyBool = x == y // b5 has type MyBool
)
 
 
另外来看下接口类型和它的实现类的比较
  • A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t's dynamic type is identical to X and t's dynamic value is equal to x.对于非接口类型X的值x和接口类型T的值t,当类型X是可比较的,且X实现了T,则它们是可比较的。当t的动态类型是X,且t的动态类型值等于x时,它们相等。
有如下实例,定义了接口Shape、Rect实现了该接口
type Shape interface {
    Area() float32
}

type Rect struct {
    width  float32
    height float32
}

func (r Rect) Area() float32 {
    return r.width * r.height
}

func main() {
    var s Shape
    s = Rect{5.0, 4.0}
    r := Rect{5.0, 4.0}
    fmt.Printf("type of s is %T\n", s)
    fmt.Printf("value of s is %v\n", s)
    fmt.Println("area of rectange s", s.Area())
    fmt.Println("s == r is", s == r)
}

输出:

type of s is main.Rect
value of s is {5 4}
area of rectange s 20
s == r is true

上面比较操作中,因为 Rect 结构体实现了Shape接口,并且type Rect是可以比较的,所以s==r,比较操作能够进行;又因为s的动态类型为Rect,且对应的动态类型值等于r,所以s等于r。

posted @ 2022-12-08 09:47  cosmoswong  阅读(270)  评论(0编辑  收藏  举报