Sobes.tech
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 append moż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 przy append jest 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ę)