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]T | Slice []T | |
|---|---|---|
| Długość | stała, część typu | zmienia się przez append |
| Przypisanie i przekazanie | kopiuje wszystkie elementy | kopiuje mały nagłówek, elementy są wspólne |
| Wartość zerowa | N elementów zerowych | nil, długość 0 |
== | tak, element po elemencie | tylko z nil |
| Klucz mapy | tak | nie |
| Typowe użycie | dane o stałym rozmiarze: hashe, współrzędne, bufory | prawie 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]Talbo slice. - Używanie tablicy tam, gdzie potrzebny jest slice.
[]int{1, 2}to slice,[2]int{1, 2}to tablica. Funkcja przyjmująca[]intnie przyjmie[2]int; przekaża[:]. - Duże tablice w pętli range.
for _, v := range bigArraynajpierw kopiuje całą tablicę. Iteruj po&bigArrayalbo 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.