Я учусь, Идут путем прохождения через Тура по Движению. Одно из упражнений там просит, чтобы я создал 2D часть dy
строки и dx
столбцы, содержащие uint8
. Мой текущий подход, который работает, является этим:
a:= make([][]uint8, dy) // initialize a slice of dy slices
for i:=0;i
Я думаю, что итерация через каждую часть для инициализации его является слишком подробной. И если бы часть имела больше размеров, то код стал бы громоздким. Существует ли краткий способ инициализировать 2D (или n-мерный) части в Движении?
Нет более краткого пути, что Вы сделали "правильный" путь; потому что части всегда одномерны, но могут быть составлены для построения более многомерных объектов. Дополнительную информацию см. в этом вопросе: Пойдите: Как двумерный array' s представление памяти .
Одна вещь можно упростить на нем, должен использовать эти 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]
Также примечание, что, если Вы использовали бы массивы вместо [1 113] части , оно может быть создано очень легко:
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]]
В случае массивов Вы не должны выполнить итерации по "внешнему" массиву и инициализировать "внутренние" массивы, поскольку массивы не являются дескрипторами, но значениями. Посмотрите сообщение в блоге Массивы, части (и строки): механика 'добавляет' для получения дополнительной информации.
Попытка примеры на эти Идут Детская площадка .
Существует два способа использовать части для создания матрицы. Давайте смотреть на различия между ними.
Первый метод:
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
вызовы не гарантируют, что Вы закончите с непрерывной матрицей, таким образом, у Вас сможет быть матрица, разделенная на память. Давайте думать о примере с два, Идут стандартные программы, которые могли вызвать это:
make([][]int, n)
для получения выделенной памяти для matrix
, получая часть памяти от 0x000 до 0x07F. make([]int, m)
, добираясь от 0x080 до 0x0FF. make
(в его собственных целях) и добирается от 0x100 до 0x17F (прямо рядом с первой строкой стандартного № 0). make([]int, m)
соответствие второму повторению цикла и добирается от 0x180 до 0x1FF для второй строки. На данном этапе мы уже получили две разделенных строки. Со вторым методом, стандартная программа делает make([]int, n*m)
для получения всей матрицы, выделенной в единственной части, гарантируя смежность. После этого цикл необходим для обновления матричных указателей на подчасти, соответствующие каждой строке.
можно играть с кодом, показанным выше в эти , Идут Детская площадка для наблюдения различия в памяти, присвоенной при помощи обоих методов. Обратите внимание, что я использовал runtime.Gosched()
только с целью получения процессора и того, чтобы вынуждать планировщик переключиться на другую стандартную программу.
, Который использовать? Вообразите худший случай с первым методом, т.е. каждая строка не является следующей в памяти за другой строкой. Затем если Ваша программа выполнит итерации через элементы матрицы (чтобы читать или записать им), то вероятно, будет больше неудачных обращений в кэш (следовательно более высокая задержка) по сравнению со вторым методом из-за худшей местности данных. С другой стороны, со вторым методом не может быть возможно получить единственную часть памяти, выделенной для матрицы из-за фрагментации памяти (распространение блоков на всем протяжении памяти), даже при том, что теоретически может быть достаточно свободной памяти для него.
Поэтому, если нет большая фрагментация памяти и матрица, которая будет выделена, достаточно огромно, Вы всегда хотели бы использовать второй метод для получения преимущества местности данных.
Можно отослать эту часть кода -
package main
import "fmt"
func main() {
var row, col int
fmt.Print("enter rows cols: ")
fmt.Scan(&row, &col)
// allocate composed 2d array
a := make([][]int, row)
for i := range a {
a[i] = make([]int, col)
}
// array elements initialized to 0
fmt.Println("a[0][0] =", a[0][0])
// assign
a[row-1][col-1] = 7
// retrieve
fmt.Printf("a[%d][%d] = %d\n", row-1, col-1, a[row-1][col-1])
// remove only reference
a = nil
// memory allocated earlier with make can now be garbage collected.
}