golang中的0个长度切片和数组

时间:2015-03-23 17:13:32

标签: arrays pointers go slice

试图找出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的数组如何在内存中查找?

1 个答案:

答案 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值。将切片切片回零长度和容量时,运行时也不会将数据指针清零。由于这两种行为,任何切片中的数据指针很少会为零。

相关问题