Go 里 interface 为什么能比较?到底在比什么?

这块:

其实是 Go 里面非常经典、非常容易懵的知识点。

因为:

很多人看到:

go 复制代码
fmt.Println(stu1 == stu2) // false
fmt.Println(stu3 == stu4) // true

会想:

txt 复制代码
明明内容都是 Tom
为什么一个 false 一个 true?

真正原因:

在于:

txt 复制代码
interface 底层到底存了什么

今天:

我们彻底讲清楚。


一、先看代码

go 复制代码
type Stu struct {
	Name string
}

type StuInt interface{}

func main() {

	var stu1, stu2 StuInt = &Stu{"Tom"}, &Stu{"Tom"}

	var stu3, stu4 StuInt = Stu{"Tom"}, Stu{"Tom"}

	fmt.Println(stu1 == stu2) // false

	fmt.Println(stu3 == stu4) // true
}

二、interface 底层到底是什么(重点)

Go 里的 interface:

底层:

其实包含两个东西:

txt 复制代码
类型(Type)
值(Value)

也就是:

txt 复制代码
interface = (T, V)

三、例如

go 复制代码
var x interface{} = 123

此时:

txt 复制代码
T = int
V = 123

四、再例如

go 复制代码
var x interface{} = "hello"

此时:

txt 复制代码
T = string
V = "hello"

五、所以 interface 本质

其实:

像一个盒子。

盒子里:

装着:

txt 复制代码
值
+
这个值的类型

六、interface 比较规则(必须记住)

两个 interface 相等:

必须同时满足:


1. 类型相同

txt 复制代码
T 相同

2. 值相同

txt 复制代码
V 相同

七、也就是说

txt 复制代码
(T1, V1) == (T2, V2)

必须:

txt 复制代码
T1 == T2
并且
V1 == V2

八、现在分析 stu1 和 stu2(重点)


代码

go 复制代码
var stu1, stu2 StuInt = &Stu{"Tom"}, &Stu{"Tom"}

九、这里放进去的是什么

注意:

你写的是:

go 复制代码
&Stu{"Tom"}

十、& 是什么

表示:

txt 复制代码
取地址

得到:

txt 复制代码
指针

十一、所以 interface 里装的是


stu1

txt 复制代码
T = *Stu
V = 0x1000

stu2

txt 复制代码
T = *Stu
V = 0x2000

十二、为什么地址不同

因为:

go 复制代码
&Stu{"Tom"}

每次:

都会:

txt 复制代码
创建新的结构体对象

内存地址:

自然不同。


十三、真正底层发生了什么

第一次:

go 复制代码
&Stu{"Tom"}

可能:

在内存:

txt 复制代码
0x1000

第二次:

go 复制代码
&Stu{"Tom"}

可能:

在:

txt 复制代码
0x2000

十四、虽然内容一样

txt 复制代码
Name 都是 Tom

但是:

txt 复制代码
指针地址不同

十五、所以比较的是

txt 复制代码
0x1000 == 0x2000

结果:

txt 复制代码
false

十六、真正核心(重点)

指针比较:

比较的是:

txt 复制代码
地址

不是:

txt 复制代码
内容

十七、所以

go 复制代码
fmt.Println(stu1 == stu2)

结果:

txt 复制代码
false

十八、现在分析 stu3 和 stu4(重点)


代码

go 复制代码
var stu3, stu4 StuInt = Stu{"Tom"}, Stu{"Tom"}

十九、这里和前面最大区别

注意:

这里:

txt 复制代码
没有 &

所以:

放进去的:

不是指针。

而是:

txt 复制代码
结构体值本身

二十、所以 interface 里装的是


stu3

txt 复制代码
T = Stu
V = Stu{Name:"Tom"}

stu4

txt 复制代码
T = Stu
V = Stu{Name:"Tom"}

二十一、现在比较什么

比较:

txt 复制代码
结构体内容

二十二、Go 结构体如何比较

Go:

会逐字段比较。


Name

txt 复制代码
Tom == Tom

成立。


二十三、所以结果

txt 复制代码
true

二十四、真正核心区别(必须理解)


指针 interface

txt 复制代码
比较地址

结构体 interface

txt 复制代码
比较字段内容

二十五、画图理解(重点)


stu1

txt 复制代码
interface
├── T = *Stu
└── V = 0x1000

stu2

txt 复制代码
interface
├── T = *Stu
└── V = 0x2000

比较

txt 复制代码
0x1000 != 0x2000

所以:

txt 复制代码
false

二十六、再看 stu3

txt 复制代码
interface
├── T = Stu
└── V = {Name:"Tom"}

stu4

txt 复制代码
interface
├── T = Stu
└── V = {Name:"Tom"}

二十七、比较

txt 复制代码
字段完全相同

所以:

txt 复制代码
true

二十八、为什么 interface 能直接 ==

因为:

interface:

底层:

知道:

txt 复制代码
类型
+
值

所以:

Go:

可以比较。


二十九、但是有坑(重点)

不是:

所有 interface 都能比较。


三十、例如 slice

go 复制代码
var a interface{} = []int{1,2}
var b interface{} = []int{1,2}

fmt.Println(a == b)

三十一、会直接 panic

因为:

txt 复制代码
slice 不可比较

三十二、为什么 slice 不可比较

因为:

slice:

底层:

包含:

txt 复制代码
指针
长度
容量

Go:

不允许:

直接 ==。


三十三、哪些类型可以比较


可以

  • int
  • string
  • bool
  • 指针
  • 数组
  • 结构体(字段都可比较)

不可以

  • slice
  • map
  • func

三十四、所以 interface 比较还有个规则

除了:

txt 复制代码
T 相同
V 相同

还必须:

txt 复制代码
V 本身是可比较类型

三十五、最经典 nil 坑(超级重要)

例如:

go 复制代码
var p *Stu = nil

var x interface{} = p

三十六、此时 x 是 nil 吗

很多新人:

会以为:

txt 复制代码
是 nil

其实:

txt 复制代码
不是

三十七、为什么

因为:

interface 里:

其实是:

txt 复制代码
T = *Stu
V = nil

三十八、真正 nil interface

必须:

txt 复制代码
T = nil
V = nil

三十九、所以

go 复制代码
fmt.Println(x == nil)

结果:

txt 复制代码
false

四十、这个是 Go 面试超级经典题

因为:

很多人:

不理解:

txt 复制代码
interface = (T, V)

四十一、最后一句总结(必须记住)

interface 底层:

本质:

txt 复制代码
(Type, Value)

两个 interface 相等:

必须:

txt 复制代码
类型相同
+
值相同

指针比较

txt 复制代码
比较地址

结构体比较

txt 复制代码
比较字段

所以:

go 复制代码
&Stu{"Tom"} != &Stu{"Tom"}

因为:

txt 复制代码
两个不同地址

而:

go 复制代码
Stu{"Tom"} == Stu{"Tom"}

因为:

txt 复制代码
结构体字段完全相同
相关推荐
codeejun1 小时前
每日一Go-70、Prometheus + Grafana 从采集到告警的完整实战(Go + Kind)
golang·grafana·prometheus
nnsix1 小时前
MVC、MVP、MVVM 架构 笔记
java·开发语言·前端
Smile_2542204182 小时前
vue3 + ts reactive方式清空表单对象
开发语言·前端·javascript
为思念酝酿的痛2 小时前
线程同步与互斥
linux·运维·服务器·后端
jjjava2.02 小时前
Java 多线程核心基础与线程安全
java·开发语言
悟乙己2 小时前
因果推断方法实践:Python实现合成控制法
开发语言·python
.千余2 小时前
【C++】C++核心语法:函数重载与缺省参数原理与避坑
c语言·开发语言·c++·经验分享·笔记·git·学习
DreamLife☼2 小时前
OpenBCI-Python与OpenBCI:实时脑电信号采集实战
开发语言·python·硬件·选型·openbci·cyton·ganglion
AI行业学习2 小时前
CC-Switch 下载、安装与使用配置指南【2026.5.29】
java·开发语言·vscode·python·eclipse·laravel