繁体   English   中英

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

[英]0 length slices and arrays in golang

试图找出0长度的数组和切片在Golang中的行为。 提出了两个代码段(我在某处找到了代码,并对其进行了一些修改以使其适用于此)

https://play.golang.org/p/ew2YYgvpGC

https://play.golang.org/p/jm2p6L6WCG

我从网站上得知,nil数组([] int(nil))的指针值为nil,因此我决定对其进行测试。 果然如此。 我只是对make和切片数组感到困惑。 对我来说,它有意外的行为。

我对这两者的行为感到非常困惑。 第一个在我的计算机和操场上运行良好。 我注意到第一个数组和最后一个数组的地址总是完全相同? 为什么?

为什么是这样?

第二个是怪异的。 该代码与上一个代码完全相同,除了len / cap之间存在其他代码片段。 它无法在运动场上运行,切片切片的最后一个错误,由于某种原因,切片的长度为3(在我的计算机上,切片的长度为0,所有切片的上限其中是272851504)。 它确实可以在我的计算机上运行。 我注意到用make创建的第一个数组的地址总是小于最后一个数组的地址。 它总是不同,并且较小(第一个),为什么? 数组地址的代码没有变化

另外,为什么make()甚至创建一个数组? 长度为0的数组在内存中怎么看?

我注意到第一个数组和最后一个数组的地址总是完全相同? 为什么?

为什么是这样?

您将函数中的地址基于函数参数中的slice头。 碰巧该函数每次都在相同的内存地址运行。 另外,作为实现细节,当您将原始文件切成零长度和零容量时,它不会使Data指针归零。 在这两个函数中,都将复制切片标头,因此您甚至不必检查原始的标头切片。

第二个示例,您没有正确读取切片头。 如果您想玩转,无需尝试进行指针算术,则可以直接获取切片的地址

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM