在本文中,我们将深入探讨interface{}
类型,并全面了解它的运作方式。
让我们深入探讨。
1. 接口实际上包含两个东西,而不是一个。
在运行时,这个过程被称为“装箱”值,你可以将interface{}
想象成这样:
type iface struct {
tab *itab
data unsafe.Pointer
}
类型描述符tab
是一个包含接口方法集、底层类型以及实现接口的底层类型的方法的小型结构体:
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
interface{}
变量中指针指向存储值的内存位置。
当提取一个interface{}
值时,Go会通过访问类型描述符和指针来“解箱”它,然后使用这些信息创建一个适当类型的新变量。这个过程由Go运行时处理。
“你是如何了解这些秘密的呢?”
你可以通过查看Go运行时存储库了解更多信息,该存储库包含了一系列函数和数据结构,这些函数和数据结构被Go运行时系统用于管理Go程序的执行。
2. 空不是空
当一个interface{}
变量持有一个nil
值时,并不意味着它等于nil
。下面是一个例子来说明这一点:
func main() {
var x interface{}
var y *int = nil
x = y
if x != nil {
fmt.Println("x != nil") // actual
} else {
fmt.Println("x == nil") // expect
}
fmt.Println(x)
}
// x != nil
// <nil>
在这个例子中,我将x赋值为nil指针int值,但实际结果是"x != nil",即使当我打印x的值时,它也显示为<nil>。
这是因为当使用"=="运算符将一个interface{}
变量与nil
进行比较时,只有当类型描述符和值数据都为nil
时才会返回true
。
“太荒谬了,我该怎么解决这个问题呢?”
我通常使用反射来解决这个问题,因为我不需要知道底层类型。我还会编写一个实用函数来检查nil
值:
func IsAnyNil(x interface{}) bool {
return reflect.ValueOf(x).IsNil()
}
“所以,interface(int64) = 1 和 interface(int32) = 1 不相等... 是吗?”
正如我们之前讨论的,你是正确的,类型为int64的interface{}
中的值1不等于类型为int32的interface{}
中的值1。为了确认这一点,我为你运行了一个测试:
func main() {
var y int32 = 1
var z int64 = 1
var x1 interface{} = y
var x2 interface{} = z
if x1 == x2 {
fmt.Println("x1 == x2") // expect
} else {
fmt.Println("x1 != x2") // actual
}
}
// x1 != x2
总结
这就结束了我们的讨论。你现在完全理解了interface{}
的工作原理,并可以自信地运用这些知识。
请记住,永远保持学习的态度,并享受其中的乐趣,愉快编码!
如果你喜欢我的文章,点赞,关注,转发!
网友评论