Nie ma bardziej zwięzłego sposobu, to, co zrobiłeś, jest „właściwą” drogą; ponieważ plasterki są zawsze jednowymiarowe, ale mogą być składane w celu konstruowania obiektów o wyższych wymiarach. Zobacz to pytanie po więcej szczegółów: Idź: Jak jest reprezentacja pamięci w dwuwymiarowej tablicy .
Jedną rzeczą, którą możesz uprościć, jest użycie for range
konstrukcji:
a := make([][]uint8, dy)
for i := range a {
a[i] = make([]uint8, dx)
}
Zwróć też uwagę, że jeśli zainicjujesz swój plasterek literałem złożonym , otrzymasz to za darmo, na przykład:
a := [][]uint8{
{0, 1, 2, 3},
{4, 5, 6, 7},
}
fmt.Println(a)
Tak, to ma swoje ograniczenia, ponieważ pozornie musisz wymienić wszystkie elementy; ale są pewne sztuczki, mianowicie nie musisz wyliczać wszystkich wartości, tylko te, które nie są zerowymi wartościami typu elementu wycinka. Aby uzyskać więcej informacji na ten temat, zobacz Keyed items in golang array initialization .
Na przykład, jeśli chcesz plasterek, w którym pierwsze 10 elementów to zera, a następnie następuje 1
i 2
, można go utworzyć w następujący sposób:
b := []uint{10: 1, 2}
fmt.Println(b)
Pamiętaj również, że jeśli zamiast plasterków użyjesz tablic , możesz je bardzo łatwo utworzyć:
c := [5][5]uint8{}
fmt.Println(c)
Wynik to:
[[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]]
W przypadku tablic nie musisz iterować po tablicy „zewnętrznej” i inicjować tablic „wewnętrznych”, ponieważ tablice nie są deskryptorami, ale wartościami. Zobacz wpis na blogu Tablice, plasterki (i ciągi): Mechanika „dołączania”, aby uzyskać więcej informacji.
Wypróbuj przykłady w Go Playground .
cannot use [5][2]string literal (type [5][2]string) as type [][]string in field value
kiedy próbuję przypisać tablicę do tego, co, jak sądzę, mówię, że Go to kawałek.Istnieją dwa sposoby tworzenia macierzy za pomocą plasterków. Przyjrzyjmy się różnicom między nimi.
Pierwsza metoda:
matrix := make([][]int, n) for i := 0; i < n; i++ { matrix[i] = make([]int, m) }
Druga metoda:
matrix := make([][]int, n) rows := make([]int, n*m) for i := 0; i < n; i++ { matrix[i] = rows[i*m : (i+1)*m] }
Jeśli chodzi o pierwszą metodę, wykonywanie kolejnych
make
wywołań nie gwarantuje, że otrzymasz ciągłą macierz, więc możesz mieć macierz podzieloną w pamięci. Pomyślmy o przykładzie z dwiema procedurami Go, które mogą to spowodować:make([][]int, n)
aby uzyskać przydzieloną pamięćmatrix
, uzyskując fragment pamięci od 0x000 do 0x07F.make([]int, m)
, przechodząc od 0x080 do 0x0FF.make
(do własnych celów) i pobiera od 0x100 do 0x17F (tuż obok pierwszego wiersza procedury # 0).make([]int, m)
odpowiada drugiej iteracji pętli i pobiera od 0x180 do 0x1FF dla drugiego rzędu. W tym momencie mamy już dwa podzielone rzędy.W przypadku drugiej metody procedura polega
make([]int, n*m)
na przydzieleniu całej macierzy w jednym wycinku, zapewniając ciągłość. Następnie potrzebna jest pętla, aby zaktualizować wskaźniki macierzy do podklasów odpowiadających każdemu wierszowi.Możesz pobawić się kodem pokazanym powyżej w Go Playground, aby zobaczyć różnicę w pamięci przypisanej za pomocą obu metod. Zauważ, że użyłem
runtime.Gosched()
tylko w celu uzyskania procesora i zmuszenia planisty do przełączenia się na inną procedurę.Którego użyć? Wyobraź sobie najgorszy przypadek w przypadku pierwszej metody, tj. Każdy wiersz nie jest w pamięci następny. Następnie, jeśli twój program iteruje przez elementy macierzy (aby je odczytać lub zapisać), prawdopodobnie będzie więcej błędów pamięci podręcznej (stąd większe opóźnienie) w porównaniu z drugą metodą z powodu gorszej lokalizacji danych. Z drugiej strony, w przypadku drugiej metody może nie być możliwe uzyskanie pojedynczego fragmentu pamięci przydzielonej do macierzy, ze względu na fragmentację pamięci (porcje rozrzucone po całej pamięci), mimo że teoretycznie może być na to dość wolnej pamięci .
Dlatego jeśli nie ma dużej fragmentacji pamięci, a macierz, która ma być przydzielona, nie jest wystarczająco duża, zawsze chciałbyś użyć drugiej metody, aby uzyskać przewagę lokalności danych.
źródło