我正在尝试创建一个2d数组:
board := make([][]string, m)
for i := range board {
board[i] = make([]string, n)
}
然而,鉴于冗长,我想知道是否有一个更好或更简洁的方法来处理这个问题(要么生成动态数组,要么一个不同的/习惯的数据结构来处理这样的棋盘游戏数据)?
背景:
- 这是一个桌面游戏
- 直到用户开始玩游戏(例如,MxN)时才知道棋盘的尺寸。
- 我想在每个单元格中存储任意字符(或单个字符串)。在我的《TicTacToe》游戏中,这将是"X"或"O"(或用户选择的任何其他角色)。
您在示例代码中构建的不是2D数组,而是切片的切片:这种类型的每个子切片可以具有不同的长度,这就是为什么您为每个子切片分别分配的原因。
如果您想用单个分配来表示电路板,那么一种选择是分配单个切片,然后使用简单的算术来确定元素的位置。例如:
board := make([]string, m*n)
board[i*m + j] = "abc" // like board[i][j] = "abc"
您描述的方法创建了一个切片的切片,它看起来类似于您想要的2d数组。我建议您将类型更改为uint8,因为您只关心3个状态nothing
/first
/second
播放器。
这将分别分配每一行(您将在基准测试中至少看到m + 1 allocs/op
)。这并不是很好,因为不能保证单独的分配将被定位在彼此接近的位置。
为了保持局部性,你可以这样做:
M := make([][]uint8, row)
e := make([]uint8, row * col)
for i := range M {
a[i] = e[i * col:(i + 1) * col]
}
这将最终只分配2次,并且片的片将保持数据局部性。请注意,您仍然可以访问2d格式的M
M[2][6]
。
一个很好的视频,它解释了如何更快地做到这一点。
对于多维数组,我们可以使用以下两种用例中的任何一种:
- 在编译 时知道数组的尺寸
- 你只有在运行时才能知道数组的尺寸,也就是从用户那里
对于用例1
matr := [5][5]int{}
对于用例2
var m, n int
fmt.Scan(&m, &n)
var mat = make([][]int, m)
for i := range mat {
mat[i] = make([]int, n)
fmt.Printf("Row %d: %vn", i, mat[i])
}
简而言之,我们必须依靠make
来创建动态数组