您现在的位置是:亿华云 > 域名
这个 Go 语言的经典 “坑”,我算是服了
亿华云2025-10-03 02:22:22【域名】6人已围观
简介大家好,我是明哥。在开始之前,先考你一个非常 Go 味的经典问题:如何判断一个 interface{} 的值是否为 nil ?这也是面试有可能会被问到的一个问题,这个问题很 “迷”,平时没有特别留心的
大家好,坑我是经典明哥。
在开始之前,算服先考你一个非常 Go 味的坑经典问题:如何判断一个 interface{ } 的值是否为 nil ?
这也是面试有可能会被问到的一个问题,这个问题很 “迷”,经典平时没有特别留心的算服朋友,很容易在这边裁了。坑
我相信很多人会下意识的经典回答,直接 v == nil 进行判断不就好了吗?算服
很久之前,我也是坑那么想的,可写了个 demo 后,经典才发现事情没那么简单。算服
请看下面这段代码,坑可以先猜测一下输出的经典结果。
package main import ( "fmt" ) func main() { var a *string = nil var b interface{ } = a fmt.Println(b==nil) }答案应该会跟你下意识的算服回答 相反。
输出的结果的是 false
这是为什么呢?接下来,我们就要好好的唠唠这里面的高防服务器道道。
1. 两个 interface 比较
interface 的内部实现包含了两个字段,一个是 type,一个是 data
对于这样一个变量
var age interface{ } = 25其实内部结构是
因此两个 interface 比较,势必与这两个字段有所关系。
经过验证,只有下面两种情况,两个 interface 才会相等。
第一种情况
type 和 data 都相等
在下面的代码中,p1 和 p2 的 type 都是 Profile,data 都是 { "iswbm"},因此 p1 与 p2 相等
而 p3 和 p3 虽然类型都是 *Profile,但由于 data 存储的是结构体的地址,而两个地址和不相同,因此 p3 与 p4 不相等
package main import "fmt" type Profile struct { Name string } type ProfileInt interface { } func main() { var p1, p2 ProfileInt = Profile{ "iswbm"}, Profile{ "iswbm"} var p3, p4 ProfileInt = &Profile{ "iswbm"}, &Profile{ "iswbm"} fmt.Printf("p1 --> type: %T, data: %v \n", p1, p1) fmt.Printf("p2 --> type: %T, data: %v \n", p2, p2) fmt.Println(p1 == p2) // true fmt.Printf("p3 --> type: %T, data: %p \n", p3, p3) fmt.Printf("p4 --> type: %T, data: %p \n", p4, p4) fmt.Println(p3 == p4) // false }运行后,输出如下
p1 --> type: main.Profile, data: { iswbm} p2 --> type: main.Profile, data: { iswbm} true p3 --> type: *main.Profile, data: 0xc00008e200 p4 --> type: *main.Profile, data: 0xc00008e210 false第二种情况
特殊情况:两个 interface 都是 nil
当一个 interface 的 type 和 data 都处于 unset 状态的时候,那么该 interface 的类型和值都为 nil
package main import "fmt" func main() { var p1, p2 interface{ } fmt.Println(p1 == p2) // true fmt.Println(p1 == nil) // true2. interface 与 非 interface 比较
当 interface 与非 interface 比较时,服务器托管会将 非interface 转换成 interface ,然后再按照 两个 interface 比较 的规则进行比较。
示例如下
package main import ( "fmt" "reflect" ) func main() { var a string = "iswbm" var b interface{ } = "iswbm" fmt.Println(a==b) // true }上面这种例子可能还好理解,那么请你看下面这个例子(文章开头的示例),为什么 b 与 nil 不相等?
package main import ( "fmt" ) func main() { var a *string = nil var b interface{ } = a fmt.Println(b==nil) // false }但当你使用 b==nil 进行判断时,其实右边的 nil 并非单纯的是我们所理解的值为nil,而正确的理解应该是 类型为 nil 且 值也为 nil。
Go 会先将 nil 转换为interface (type=nil, data=nil) ,这与 b (type=*string, data=nil) 虽然 data 是一样的,但 type 不相等,因此他们并不相等。
那有没有办法判断一个 interface{ } 是不是 nil 呢?
有办法的,但是要借助反射,一个非万不得已不会使用的 reflect 包。
package main import ( "fmt" "reflect" ) func IsNil(i interface{ }) bool { vi := reflect.ValueOf(i) if vi.Kind() == reflect.Ptr { return vi.IsNil() } return false } func main() { var a *string = nil var b interface{ } = a fmt.Println(IsNil(b)) }本文通过一些例子介绍了 Go 在比较时候,内部的一些实现原理,对于很多人,香港云服务器可能是一个“新”知识,没有掌握的话,一定会在以后在编码过程中给自己挖了个“大坑”,而这种语言内部的 “坑”,不知道就是不知道,再怎么代码走查都很难发现。希望通过本篇文章,带你一起把这个“坑” 给填上。
本篇原属于 Go 面试题库专栏系列文章,以前都是在标题上写明了是面试题,考虑到有些人最近没有在面试,怕你们错过这类即使不面试,也要掌握的知识,以后的内容,可能不会在标题上特别标明是面试题了。
本专栏系列文章,我都公开到 Github 上:https://github.com/iswbm/golang-interview
这个号没有留言功能呢 ,如果文章有写得不对的地方,可以去那里提交 issue 帮我指正。顺便可以帮我点个小 ??,在那里我对题库进行了分类整理,方便索引查找。
加油噢,我们下篇见!
很赞哦!(56)
上一篇: 全线新品重磅亮相,宁畅以“冷静计算”推动行业长远发展
下一篇: 应对气候危机对数据中心的影响