在Java中,正如我们所知,二维数组是多维一维数组.这意味着那些一维数组在内存上不连续.
相反,在C中,二维数组实际上是一维数组,其大小为total_row*total_column.因为Go语言使用了C语言中的许多概念.所以我的问题是:Go中的二维数组的内存表示看起来像是C还是Java?
1> icza..:
在Go中,切片经常被误认为数组,所以我回答两者.
数组引用规范:数组类型:
数组类型总是一维的,但可以组成以形成多维类型.
在那里,你的答案清晰明了.但答案不仅仅是因为数组是Go中的值,它们不是像切片那样的描述符(标题).
看这个简单的例子:
x := [5][5]byte{} fmt.Println(&x[0][3]) fmt.Println(&x[0][4]) fmt.Println(&x[1][0])输出(在Go Playground上试试):
0x10432203 0x10432204 0x10432205如您所见,为数组分配和使用的内存是连续的:第二行从内存地址开始,该内存地址是第一行的最后一个元素的地址之后.
检查数组的大小:
fmt.Println(unsafe.Sizeof([4][6]int{})) // 96 fmt.Println(unsafe.Sizeof([6][4]int{})) // 96如果切换行和列并不重要,它的大小是相同的.
片在切片的情况下也是如此:多维切片是切片切片.规格:切片类型:
切片是底层数组的连续段的描述符,并提供对该数组中编号的元素序列的访问. ... 像数组一样,切片总是一维的,但可以组成以构造更高维的对象.
切片是描述符,切片头包含指向底层(支持)数组元素的指针,长度和容量.因此,总切片的数量在内存使用方面很重要.
看这个例子:
x := make([][]byte, 2) for i := range x { x[i] = make([]byte, 1000) } fmt.Println(len(x), len(x)*len(x[0])) y := make([][]byte, 1000) for i := range y { y[i] = make([]byte, 2) } fmt.Println(len(y), len(y)*len(y[0]))输出(在Go Playground上试试):
2 2000 1000 2000既x和y多维片具有2000个元素总(2000个字节),但x存储2仅切片,每个具有1000元件,而y存储1000切片,每个具有2元件.
这意味着x需要2切片头,同时y需要1000切片头(对于元素,+1为x和y他们自己)!
切片标头由reflect.SliceHeader以下表示:
type SliceHeader struct { Data uintptr Len int Cap int }32位体系结构上的片头大小为12字节,64位体系结构上的大小为24字节.因此,如果32位arch元素x需要2,000字节加上内存中的2x12字节,即2,024字节,而元素y需要2,000字节加上1,000*12即14,000字节.
另请注意,多维切片的元素可能包含不同长度的切片:
对于数组阵列,内部数组通过构造始终具有相同的长度; 然而,对于切片(或切片阵列),内部长度可以动态变化.而且,内部切片必须单独初始化.
就像在这个例子中:
x := make([][]byte, 2) x[0] = []byte{1, 2} x[1] = []byte{1, 2, 3, 4} fmt.Println(x[0]) fmt.Println(x[1])输出(在Go Playground上试试):
[1 2] [1 2 3 4]如果您还没有阅读,推荐:Go Blog:数组,切片(和字符串):'追加'的机制