• Go语言中的陷进:两个 nil 可能不相等
  • 发布于 2个月前
  • 200 热度
    0 评论
概述
interface 类型对应的运行时底层数据结构内部实现包含 2 个字段, 类型 Type 和 值 Value。一个接口只有 Type == nil 并且 Value == unset 状态 (nil),该接口才等于 nil 。

比较规则:
• 两个 接口值 进行比较时,先比较 Type,再比较 Value
• 接口值 与 非接口值 进行比较时,先将 非接口值 转换为 接口值,然后再进行比较

两个 nil 可能不相等
package main
import (
    "fmt"
)
// 堆代码 www.duidaima.com
func main() {
    var p *int = nil
    var v interface{} = p // 赋值完成
    fmt.Println(v == p)   // true
    fmt.Println(p == nil) // true
    fmt.Println(v == nil) // false
}

// $ go run main.go
// 输出如下
/**
  true
  true
  false
*/
代码说明
上面的示例代码中,将一个 指针 nil 值 p 赋值给 接口 nil 值 v, 赋值完成后,v 的内部字段为 (Type = *int, Value = nil) 。
1. 第一个比较: v 与 p 比较时,将 p 转换为接口类型后再进行比较
• p 转换为接口类型后等于 (Type = *int, Value = nil)
• v 等于 (Type = *int, Value = nil)
• 两者相等
2. 第二个比较: p 与 nil 比较时,直接比较值,两者相等
3. 第三个比较: v 与 nil 比较时,将 nil 转换为接口类型后再进行比较
• nil 转换为接口类型后等于 (Type = nil, Value = nil)
• v 等于 (Type = *int, Value = nil)
• 两者不相等

接口类型和 nil 可能不相等
非空接口的运行时使用 runtime.iface 结构体表示,原型如下:
type iface struct {
    tab  *itab
    data unsafe.Pointer
}
其中,仅当 tab 和 data 字段都为 nil 时, 接口类型值才等于 nil。
package main

import (
    "fmt"
)

func main() {
    var a interface{} = nil         // tab = nil, data = nil, 所以 a == nil
    var b interface{} = (*int)(nil) // tab 包含 *int 类型信息, data = nil, 所以 b != nil

    fmt.Println(a == nil) // true
    fmt.Println(b == nil) // false
}
// 堆代码 www.duidaima.com
// $ go run main.go
// 输出如下
/**
  true
  false
*/

用户评论