Menu

Tablice w Go (Golang): stała długość, kopiowanie i slice'y

Tablica w Go ma stałą długość, która jest częścią jej typu, i jest kopiowana przy przypisaniu. Zobacz, jak deklarować, przeglądać, porównywać i przekazywać tablice oraz dlaczego większość kodu w Go używa slice'ów.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Deklarowanie tablicy

Typ tablicowy zapisuje się jako [N]T: najpierw długość, potem typ elementu. Długość jest ustalana w czasie kompilacji i jest częścią typu.

Wynik:

[90 0 0 0 75] 5
Tue
[5]int [2 3 5 7 11]
["" "b" "" "d" ""]

Tablica jest zawsze w pełni zainicjalizowana. Elementy, którym nie przypiszesz wartości, mają wartość zerową typu elementu: 0, "", false, nil.

Indeksy i granice

Indeksy biegną od 0 do len(a)-1. Stały indeks poza zakresem to błąd kompilacji. Zmienny indeks poza zakresem wywołuje panic w czasie działania programu.

var a [3]int
a[5] = 1 // compile error: invalid argument: index 5 out of bounds [0:3]

i := 5
a[i] = 1 // panic: runtime error: index out of range [5] with length 3

Iterowanie

for i, v := range a odwiedza kolejno każdy element. v jest kopią elementu, więc przypisanie do v nie zmienia tablicy. Zapisuj przez indeks.

Jest jeszcze jeden niuans typowy dla tablic: range po wartości tablicy na początku oblicza jej kopię. Jeśli ciało pętli zmienia dalsze elementy, v nadal pokazuje stare wartości. Iterowanie po &a lub a[:] pozwala uniknąć kopii.

Tablice są wartościami

To główna różnica w porównaniu z tablicami w C, Javie czy JavaScripcie. Przypisanie tablicy kopiuje każdy element. Przekazanie tablicy do funkcji też ją kopiuje.

Wynik:

[1 2 3] [99 2 3]
[1 2 3]
[0 2 3]

Kopiowanie jest tanie dla małych tablic i drogie dla dużych: przekazanie [1_000_000]int przez wartość kopiuje osiem megabajtów. Przekaż wskaźnik (*[N]T) lub slice (a[:]), gdy tablica jest duża albo funkcja ma ją zmienić. Indeksowanie przez wskaźnik do tablicy nie wymaga jawnego *: a[0] działa na *[3]int.

Porównywanie tablic i używanie ich jako kluczy mapy

Tablice porównywalnych elementów obsługują == i !=. Dwie tablice są równe, gdy każdy element jest równy. Dzięki temu mogą być kluczami mapy, czego slice'y nie potrafią.

Tablice o różnych długościach to różne typy i w ogóle nie da się ich porównać: [3]int{} == [4]int{} się nie kompiluje (mismatched types [3]int and [4]int).

Tablice wielowymiarowe

Tablica tablic daje stałą siatkę. Cała siatka to jeden ciągły blok pamięci.

row[:] zamienia wiersz [3]rune w slice []rune, który przyjmuje string().

Tablica a slice

Tablica [N]TSlice []T
Długośćstała, część typuzmienia się przez append
Przypisanie i przekazaniekopiuje wszystkie elementykopiuje mały nagłówek, elementy są wspólne
Wartość zerowaN elementów zerowychnil, długość 0
==tak, element po elemencietylko z nil
Klucz mapytaknie
Typowe użyciedane o stałym rozmiarze: hashe, współrzędne, buforyprawie wszystko inne

W praktyce tablice spotkasz głównie w kilku miejscach: sha256.Sum256 zwraca [32]byte, tablice wyszukiwania o niezmiennym rozmiarze oraz jako pamięć bazowa slice'a. Wycięcie tablicy przez a[:] lub a[1:3] tworzy slice, który dzieli z nią pamięć; strona o slice'ach wyjaśnia, co oznacza to współdzielenie.

Konwersja między tablicami a slice'ami

Konwersja slice'a na tablicę (Go 1.20) lub na wskaźnik do tablicy (Go 1.17) wywołuje panic, jeśli slice jest krótszy niż długość tablicy: panic: runtime error: cannot convert slice with length 2 to array or pointer to array with length 3.

Typowe błędy

  • Oczekiwanie, że funkcja zmieni tablicę przekazaną jako argument. Dostaje kopię. Przekaż *[N]T albo slice.
  • Używanie tablicy tam, gdzie potrzebny jest slice. []int{1, 2} to slice, [2]int{1, 2} to tablica. Funkcja przyjmująca []int nie przyjmie [2]int; przekaż a[:].
  • Duże tablice w pętli range. for _, v := range bigArray najpierw kopiuje całą tablicę. Iteruj po &bigArray albo po slice'ie.

Najczęściej zadawane pytania

Jak zadeklarować tablicę w Go?

Wpisz długość w nawiasach kwadratowych przed typem elementu: var a [5]int tworzy pięć zer. Z wartościami: a := [3]string{"x", "y", "z"}. Użyj [...], aby kompilator sam policzył elementy: a := [...]int{1, 2, 3} ma typ [3]int.

Czym różni się tablica od slice'a w Go?

Tablica ma stałą długość, która jest częścią jej typu ([3]int i [4]int to różne typy), i jest kopiowana przy przypisaniu lub przekazaniu. Slice ([]int) to widok na tablicę bazową z długością, która może się zmieniać przez append, a skopiowanie slice'a kopiuje tylko widok, nie elementy. Większość kodu w Go używa slice'ów.

Jak sprawdzić długość tablicy w Go?

Użyj wbudowanej funkcji len(a). Dla tablicy jest to stała znana w czasie kompilacji, więc możesz jej używać w wyrażeniach stałych. cap(a) zwraca tę samą liczbę.

Czy w Go można porównywać tablice?

Tak, operatorami == i !=, jeśli typ elementu jest porównywalny. Dwie tablice są równe, gdy wszystkie ich elementy są równe. Tablice mogą też być kluczami mapy. Slice'ów nie da się porównać przez == (poza porównaniem z nil); do nich użyj slices.Equal.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ