Что краткий путь состоит в том, чтобы создать 2D часть в Движении?

Я учусь, Идут путем прохождения через Тура по Движению. Одно из упражнений там просит, чтобы я создал 2D часть dy строки и dx столбцы, содержащие uint8. Мой текущий подход, который работает, является этим:

a:= make([][]uint8, dy)       // initialize a slice of dy slices
for i:=0;i

Я думаю, что итерация через каждую часть для инициализации его является слишком подробной. И если бы часть имела больше размеров, то код стал бы громоздким. Существует ли краткий способ инициализировать 2D (или n-мерный) части в Движении?

62
задан 1 October 2016 в 12:11

3 ответа

Нет более краткого пути, что Вы сделали "правильный" путь; потому что части всегда одномерны, но могут быть составлены для построения более многомерных объектов. Дополнительную информацию см. в этом вопросе: Пойдите: Как двумерный 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]]

В случае массивов Вы не должны выполнить итерации по "внешнему" массиву и инициализировать "внутренние" массивы, поскольку массивы не являются дескрипторами, но значениями. Посмотрите сообщение в блоге Массивы, части (и строки): механика 'добавляет' для получения дополнительной информации.

Попытка примеры на эти Идут Детская площадка .

94
ответ дан 31 October 2019 в 14:09

Существует два способа использовать части для создания матрицы. Давайте смотреть на различия между ними.

Первый метод:

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 вызовы не гарантируют, что Вы закончите с непрерывной матрицей, таким образом, у Вас сможет быть матрица, разделенная на память. Давайте думать о примере с два, Идут стандартные программы, которые могли вызвать это:

  1. стандартные выполнения № 0 make([][]int, n) для получения выделенной памяти для matrix, получая часть памяти от 0x000 до 0x07F.
  2. Затем это запускает цикл и делает первую строку make([]int, m), добираясь от 0x080 до 0x0FF.
  3. Во втором повторении это вытесняется планировщиком.
  4. планировщик дает процессор стандартному № 1, и он начинает работать. Этот также использует make (в его собственных целях) и добирается от 0x100 до 0x17F (прямо рядом с первой строкой стандартного № 0).
  5. Через некоторое время, это становится вытесненным, и стандартный № 0 начинает работать снова.
  6. Это делает make([]int, m) соответствие второму повторению цикла и добирается от 0x180 до 0x1FF для второй строки. На данном этапе мы уже получили две разделенных строки.

Со вторым методом, стандартная программа делает make([]int, n*m) для получения всей матрицы, выделенной в единственной части, гарантируя смежность. После этого цикл необходим для обновления матричных указателей на подчасти, соответствующие каждой строке.

можно играть с кодом, показанным выше в эти , Идут Детская площадка для наблюдения различия в памяти, присвоенной при помощи обоих методов. Обратите внимание, что я использовал runtime.Gosched() только с целью получения процессора и того, чтобы вынуждать планировщик переключиться на другую стандартную программу.

, Который использовать? Вообразите худший случай с первым методом, т.е. каждая строка не является следующей в памяти за другой строкой. Затем если Ваша программа выполнит итерации через элементы матрицы (чтобы читать или записать им), то вероятно, будет больше неудачных обращений в кэш (следовательно более высокая задержка) по сравнению со вторым методом из-за худшей местности данных. С другой стороны, со вторым методом не может быть возможно получить единственную часть памяти, выделенной для матрицы из-за фрагментации памяти (распространение блоков на всем протяжении памяти), даже при том, что теоретически может быть достаточно свободной памяти для него.

Поэтому, если нет большая фрагментация памяти и матрица, которая будет выделена, достаточно огромно, Вы всегда хотели бы использовать второй метод для получения преимущества местности данных.

6
ответ дан 31 October 2019 в 14:09

Можно отослать эту часть кода -

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.
}

Ссылка

0
ответ дан 31 October 2019 в 14:09