试图找出0长度数组和切片在Golang中的表现。想出了两段代码(我在某处发现了代码并对其进行了一些修改以便使用它)
https://play.golang.org/p/ew2YYgvpGC
https://play.golang.org/p/jm2p6L6WCG
我从网站上了解到nil数组([] int(nil))的指针值为nil,所以我决定测试一下。果然,就是这样。我只是对make和切片数组感到困惑。它对我有意想不到的行为。
我对这两个人的行为感到很困惑。第一个在我的电脑和操场上运行良好。我注意到第一个和最后一个数组的地址总是完全相同?为什么呢?
为什么会这样?
第二个是怪异的。这是与前一个完全相同的代码,除了在其间有len / cap的其他代码片段。它不会在go操场上运行,最后一个带有切片阵列的错误,由于某种原因,切片的长度为3(在我的计算机上,最后一个为0,所有的上限他们是272851504)。然而它确实在我的电脑上运行。我注意到用make创建的第一个数组的地址总是小于最后一个数组。它总是不同的,有点小(第一个),为什么?数组地址的代码没有变化
另外,为什么make()甚至会创建一个数组?长度为0的数组如何在内存中查找?
答案 0 :(得分:3)
我注意到第一个和最后一个数组的地址总是如此 完全相同?为什么呢?
为什么会这样?
您将函数中的地址基于函数参数中的切片标头。偶然,每次都会在同一个内存地址运行该函数。此外,作为一个实现细节,当您将原始片段切割为零长度和容量时,它不会将数据指针清零。在这两个函数中,都会复制切片标头,因此您甚至不会检查原始标头切片。
第二个例子,你没有正确读出切片头。 如果你想玩,你不需要尝试做指针运算,你可以直接获取切片的地址
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
但是,如果你真的想通过指针算法检查切片头,也许这可以更好地说明你需要做什么:https://play.golang.org/p/GL6NtyPNs8
func InspectSlice(slice *[]int) {
// Get the header directly by converting it to a reflect.SliceHeader
hdr := (*reflect.SliceHeader)(unsafe.Pointer(slice))
// Create a header for comparison via pointer manipulation
address := (uintptr)(unsafe.Pointer(slice))
lenAddr := address + unsafe.Sizeof(address)
capAddr := lenAddr + unsafe.Sizeof(int(0))
unsafeHdr := reflect.SliceHeader{
Data: *(*uintptr)(unsafe.Pointer(address)),
Len: *(*int)(unsafe.Pointer(lenAddr)),
Cap: *(*int)(unsafe.Pointer(capAddr)),
}
fmt.Printf("Real Header: %#v\n", *hdr)
fmt.Printf("UnsafeHeader: %#v\n", unsafeHdr)
}
另外,为什么make()甚至会创建一个数组?
Make不会创建数组,而您标记为array
的只是一个切片文字。
长度为0的数组如何在内存中查找?
它看起来不像什么。它消耗0个字节。
制作零长度切片时所看到的很可能是指向全局零值数组的指针。制作一堆不同类型的零长度切片,数据指针将全部相同。正如所有空struct{}
和空nil interface{}
都被赋予与优化相同的值。这完全是一个实现细节,因为您不希望访问该Data值。将切片切片回零长度和容量时,运行时也不会将数据指针清零。由于这两种行为,任何切片中的数据指针很少会为零。