Junior
Jak działają slices w Go?
sobes.tech AI
Odpowiedź od AI
Slicing to lekka powłoka nad tablicą. Nie przechowuje danych samodzielnie, lecz odwołuje się do tablicy bazowej.
Struktura slice:
- Wskaźnik do tablicy bazowej: Adres pierwszego elementu slice w pamięci.
- Długość (Length): Liczba elementów w slice.
- Pojemność (Capacity): Liczba elementów w tablicy bazowej dostępnych od wskaźnika slice.
// Przykład deklaracji slice
var s []int
s = append(s, 1, 2, 3) // Dodanie elementów
// Wewnętrzne przedstawienie slice s (uproszczone)
// struct SliceHeader {
// Data uintptr // Wskaźnik do tablicy bazowej
// Len int // Długość slice
// Cap int // Pojemność slice
// }
- Tworząc slice za pomocą
make([]T, length, capacity)tworzy się tablicę bazową o podanej pojemności i slice odwołujący się do niej z podaną długością. - Używając wycinka na tablicy lub innym slice (np.
arr[low:high:max]) tworzy się nowy slice, który odwołuje się do tego samego obszaru pamięci tablicy bazowej, ale z innym wskaźnikiem, długością i pojemnością. - Operacja
appendmoże spowodować rezerwację pamięci. Jeśli obecna pojemność nie wystarcza do dodania nowych elementów, Go tworzy nową, większą tablicę bazową, kopiuje stare elementy i aktualizuje wskaźnik slice na nową tablicę. Nazywa się to realokacją. Wzrost pojemności przyappendjest wykładniczy (podwaja się do pewnego rozmiaru, potem zwalnia). - Slice są przekazywane przez wartość, ale ponieważ zawierają wskaźnik do tablicy bazowej, zmiany elementów slice (przez indeks) będą widoczne we wszystkich slice odwołujących się do tego samego tablicy.
- Zmiana długości slice przez wycinek nie wpływa na tablicę bazową, ale może ograniczyć dostęp do części danych tej tablicy.
Tabela: Porównanie długości i pojemności
| Charakterystyka | Długość (Length) | Pojemność (Capacity) |
|---|---|---|
| Definicja | Rzeczywista liczba elementów w slice | Maksymalna liczba elementów, które mogą się znaleźć w slice bez rezerwacji pamięci |
| Dostęp | Używany do dostępu do elementów (s[i]) | Określa, ile jeszcze elementów można dodać przez append przed rezerwacją pamięci |
| Uzyskanie | len(s) |
cap(s) |
// Przykład pracy z pojemnością i długością
s := make([]int, 0, 5) // Długość 0, pojemność 5
fmt.Println(len(s), cap(s)) // 0 5
s = append(s, 1, 2) // Dodanie 2 elementów
fmt.Println(len(s), cap(s)) // 2 5
s = append(s, 3, 4, 5, 6) // Dodanie kolejnych 4 elementów, wymaga rezerwacji
fmt.Println(len(s), cap(s)) // 6 10 (pojemność zwiększyła się)