1.数据类型

golang中能够用 == 号直接比较的数据类型有如下

  • 整型 integer、浮点型 float、字符串 string、布尔型 boolean、复数型 complex、指针型 pointer、通道型 channel、接口型 interface、数组型 array

不能直接比较的

  • 切片型 slice、键值对型 map、函数型 func

2.struct比较

1.相同结构体+可比较类型

package main

import "fmt"

type S struct {
	s string
	i int
	b bool
}

func main() {
	s1 := S{
		s: "你好",
		i: 1,
		b: false,
	}

	s2 := S{
		s: "你好",
		i: 1,
		b: false,
	}

	fmt.Println(s1 == s2)
}

//结果:
true

结构体内都是可比较的类型,赋值两个一样数据的struct,最终两个struct是相等的,返回true

package main

import "fmt"

type S struct {
	s string
	i int
	b bool
	p *int
}

func main() {
	s1 := S{
		s: "你好",
		i: 1,
		b: false,
        p: new(int),
	}

	s2 := S{
		s: "你好",
		i: 1,
		b: false,
		p: new(int),
	}

	fmt.Println(s1 == s2)
    fmt.Println(s1.p)
	fmt.Println(s2.p)
}

//结果
false
0xc000018080
0xc000018088

加了指针类型后依然可以直接比较,但是为什么会返回false呢?因为在初始化s1和s2的时候给p初始化了,两个指针的地址是不同的,导致返回false

如果不给p赋值,则地址为nil,或者赋同一个值,则会返回true,如下

package main

import "fmt"

type S struct {
	s string
	i int
	b bool
	p *int
}

func main() {
	pp := new(int)
	*pp = 123

	s1 := S{
		s: "你好",
		i: 1,
		b: false,
		p: pp,
	}

	s2 := S{
		s: "你好",
		i: 1,
		b: false,
		p: pp,
	}

	fmt.Println(s1 == s2)
	fmt.Println(s1.p)
	fmt.Println(s2.p)
}

//结果
true
0xc00010c008
0xc00010c008

可见此时s1和s2指针的地址是相同的

2.相同结构体+不可比较类型

package main

import "fmt"

type S struct {
	s     string
	i     int
	b     bool
	slice []int
}

func main() {
	s1 := S{
		s:     "你好",
		i:     1,
		b:     false,
		slice: []int{1, 2},
	}

	s2 := S{
		s:     "你好",
		i:     1,
		b:     false,
		slice: []int{1, 2},
	}

    fmt.Println(s1 == s2)
    //此时编译都无法通过,报错误,因为结构体里包含不可比较类型切片 []int
}

//结果
# command-line-arguments
./01_go_struct_compare.go:27:17: invalid operation: s1 == s2 (struct containing []int cannot be compared)

那么有什么办法可以让两个包含不可比较类型的结构体比较吗?可以通过 reflect.DeepEqual 函数

package main

import (
	"fmt"
	"reflect"
)

type S struct {
	s     string
	i     int
	b     bool
	slice []int
}

func main() {
	s1 := S{
		s:     "你好",
		i:     1,
		b:     false,
		slice: []int{1, 2},
	}

	s2 := S{
		s:     "你好",
		i:     1,
		b:     false,
		slice: []int{1, 2},
	}

	fmt.Println(reflect.DeepEqual(s1, s2))
}

//结果
true

reflect.DeepEqual函数深度比较的规则

  • 不同类型的值永远不会完全相等

  • 当数组值的对应元素深度相等时,数组值深度相等

  • 如果结构体的相应字段深度相等,则结构体深度相等

  • 如果func都为nil,则func深度相等,否则不会深度相等

  • 切片深度相等的条件

    • 它们都是 nil 或都非 nil,且具有相同的长度
    • 非 nil 空切片和 nil 切片(例如,[]byte{} 和 []byte(nil))并不完全相等
    • 指向同一底层数组的初始位置要相同(即 &x[0 ] == &y[0]) 或其对应的元素(直到末尾)深度相等
  • 指针深度相等的条件

    • 指针值使用 Go 的 == 运算符相等
    • 它们指向深度相等的值,则它们是深度相等的
  • 映射值map深度相等的条件

    • 它们都是 nil 或都非 nil,且具有相同的长度
    • 它们是相同的映射对象,或者它们对应的键(使用 Go 相等性匹配)映射到深度相等的值

3.不同结构体+可比较类型

可以通过强制类型转换的方式来进行比较

package main

import "fmt"

type S1 struct {
	s string
	i int
	b bool
	p *int
}

type S2 struct {
	s string
	i int
	b bool
	p *int
}

func main() {
	var s1 S1
	var s2 S2

	//s1 = s2 //报错,无法直接赋值
	s3 := S1(s2)
	fmt.Println(s3 == s1)
}

//结果
true

4.不同结构体+不可比较类型

package main

import "fmt"

type S1 struct {
	s string
	i int
	b bool
	p *int
	slice []int
}

type S2 struct {
	s string
	i int
	b bool
	p *int
	slice []int
}

func main() {
	var s1 S1
	var s2 S2

	s3 := S1(s2)
	fmt.Println(s3 == s1)
}

//结果
# command-line-arguments
./02_go_struct_compare.go:26:17: invalid operation: s3 == s1 (struct containing []int cannot be compared)

可见如果结构体里包含了不可比较类型,则无法通过强制类型转换的方式进行比较

5.struct作为map的key

struct里面的类型必须是可比较的,才能作为map的key,否则会报错,无法通过编译

package main

import "fmt"

type S1 struct {
	s string
	i int
	b bool
	p *int
	slice []int
}

func main() {
	m := make(map[S1]string, 0)	//编译出错
	fmt.Println(m)
}

//结果
# command-line-arguments
./02_go_struct_compare.go:27:12: invalid map key type S1