使用 make 或默认初始化的不同大小的数组

Different sizes of arrays using make or default initialization

我是 Go 的新手,我试图理解这门语言以编写高效的代码。在下面的代码中,两个数组的大小相差 140%,谁能解释一下?

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    ind1 := make([]bool, 10)
    var ind2 [10]bool
    fmt.Println(unsafe.Sizeof(ind1)) // 24
    fmt.Println(len(ind1)) // 10
    fmt.Println(unsafe.Sizeof(ind2)) // 10
    fmt.Println(len(ind2)) // 10
}

即使明确设置了容量,第一个数组的大小仍为 10:

    ind1 := make([]bool, 10, 10)

谁能解释一下?使用 make 是否有任何额外开销?如果是,为什么建议使用make over default initialization?

ind1是一个切片(类型是[]bool)。

ind2是一个数组(类型是[10]bool)。

它们不是同一类型。

unsafe.Sizeof(ind1) 的结果可能与传递给 make 的参数无关。

Arrays and slices 在 Go 中是不同的东西。

你的ind1是一个切片,ind2是一个数组。数组的长度是类型的一部分,因此例如 [2]bool[3]bool 是 2 种不同的数组类型。

Go 中的切片是底层数组的 连续段 的描述符,并提供对该数组中元素的编号序列的访问。这个切片头是一个 struct-like 数据结构,由 reflect.SliceHeader:

类型表示
type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

它包含一个数据指针(指向所表示段的第一个元素)、一个长度和一个容量。

unsafe.SizeOf() 函数 returns 假设变量的大小(以字节为单位),就好像它将保存传递的值一样。 它不包括它可能引用的任何内存。

所以如果你传递一个切片值(ind1),它会告诉你上面提到的切片头的大小。请注意,SliceHeader 字段的大小取决于体系结构,例如int 在一个平台上可能是 4 个字节,在另一个平台上可能是 8 个字节。大小 24 适用于 64 位架构。

Go Playground 在 32 位架构上运行。让我们看这个例子:

fmt.Println(unsafe.Sizeof(make([]bool, 10)))
fmt.Println(unsafe.Sizeof(make([]bool, 20)))

fmt.Println(unsafe.Sizeof([10]bool{}))
fmt.Println(unsafe.Sizeof([20]bool{}))

输出(在 Go Playground 上尝试):

12
12
10
20

如您所见,无论您传递给 unsafe.SizeOf() 的切片长度如何,在 Go Playground 上它总是 returns 12(在 64 位架构上为 24)。

另一方面,数组值包括它的所有元素,因此,它的大小取决于它的长度。 [10]bool的大小为10,[20]bool的大小为20。

查看相关问答,了解切片、数组以及它们之间的区别和关系:

必读博文:

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'