Answers:
没有一种更简洁的方法,您所做的就是“正确”的方法。因为切片始终是一维的,但可以组成更高维度的对象。有关更多详细信息,请参见此问题:Go:二维数组的内存表示如何。
您可以简化的一件事是使用for range
构造:
a := make([][]uint8, dy)
for i := range a {
a[i] = make([]uint8, dx)
}
另请注意,如果您使用复合文字初始化切片,则会获得“免费”,例如:
a := [][]uint8{
{0, 1, 2, 3},
{4, 5, 6, 7},
}
fmt.Println(a) // Output is [[0 1 2 3] [4 5 6 7]]
是的,这似乎有其局限性,因为您似乎必须枚举所有元素。但是有一些技巧,即您不必枚举所有值,只需枚举不是切片元素类型的零值的那些值即可。有关此的更多详细信息,请参阅golang数组初始化中的键控项。
例如,如果您想要一个前10个元素为零的切片,然后跟随1
和2
,则可以这样创建切片:
b := []uint{10: 1, 2}
fmt.Println(b) // Prints [0 0 0 0 0 0 0 0 0 0 1 2]
还要注意,如果使用数组而不是slice,则可以很容易地创建它:
c := [5][5]uint8{}
fmt.Println(c)
输出为:
[[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
如果是数组,则不必迭代“外部”数组并初始化“内部”数组,因为数组不是描述符而是值。请参阅博客文章数组,切片(和字符串):有关更多详细信息,请参见“追加”的机制。
在Go Playground上尝试示例。
有两种使用切片创建矩阵的方法。让我们看看它们之间的区别。
第一种方法:
matrix := make([][]int, n)
for i := 0; i < n; i++ {
matrix[i] = make([]int, m)
}
第二种方法:
matrix := make([][]int, n)
rows := make([]int, n*m)
for i := 0; i < n; i++ {
matrix[i] = rows[i*m : (i+1)*m]
}
关于第一种方法,进行连续make
调用并不能确保您最终得到一个连续的矩阵,因此可能会将矩阵划分到内存中。让我们考虑一个带有两个Go例程的示例,这可能会导致这种情况:
make([][]int, n)
以获取分配的内存matrix
,从0x000到0x07F获取一块内存。make([]int, m)
,从0x080到0x0FF。make
(出于自己的目的),并且从0x100到0x17F(紧接例程#0的第一行)。make([]int, m)
与第二个循环迭代相对应,第二行从0x180到0x1FF。至此,我们已经得到了两行。使用第二种方法,例程可以make([]int, n*m)
确保在单个切片中分配所有矩阵,从而确保连续性。之后,需要一个循环来更新指向与每一行相对应的子片段的矩阵指针。
您可以在Go Playground中使用上面显示的代码来查看使用这两种方法分配的内存的差异。请注意,我runtime.Gosched()
仅用于产生处理器并强制调度程序切换到另一个例程的目的。
使用哪一个?想象一下第一种方法的最坏情况,即,每一行在内存中都不是另一行。然后,如果您的程序遍历矩阵元素(以读取或写入它们),则由于第二种方法的数据局部性较差,与第二种方法相比,可能会有更多的缓存未命中(因此延迟时间更长)。另一方面,使用第二种方法,由于理论上内存碎片(块散布在整个内存中),即使在理论上可能有足够的可用内存,也可能无法为矩阵分配单个内存。
因此,除非存在大量的内存碎片,并且要分配的矩阵足够大,否则您总是想使用第二种方法来利用数据局部性。
在先前的答案中,我们没有考虑初始长度未知的情况。对于这种情况,您可以使用以下逻辑来创建矩阵
items := []string{"1.0", "1.0.1", "1.0.2", "1.0.2.1.0"}
mx := make([][]string, 0)
for _, item := range items {
ind := strings.Count(item, ".")
for len(mx) < ind+1 {
mx = append(mx, make([]string, 0))
}
mx[ind] = append(mx[ind], item)
}
fmt.Println(mx)
cannot use [5][2]string literal (type [5][2]string) as type [][]string in field value
当我尝试将数组分配给我想告诉Go的是切片时,我得到了。