W Go struktura map zawsze jest przekazywana przez wartość, ale ta wartość zawiera wskaźnik do wewnętrznych struktur samej map (pod maską – tabela haszowa). Dlatego jeśli przekazujesz map do funkcji i wewnątrz funkcji zmieniasz zawartość (dodajesz/usuwasz elementy), zmiany będą widoczne na zewnątrz. Podobnie zachowują się slice – kopiowana jest struktura slice, ale nie sama tablica-dane: slice zawiera wskaźnik do tablicy, długość i pojemność. Jeśli zmieniasz wartości po indeksie wewnątrz funkcji, pierwotna tablica również ulegnie zmianie. Ale jeśli z funkcji przypisujesz nowy slice (na przykład, reslice), pierwotna zmienna się nie zmieni.
func updateMap(m map[string]int) { m["key"] = 42 // Zmiany są widoczne na zewnątrz! } func updateSlice(s []int) { s[0] = 99 // Zmienia się pierwotna tablica }
Dlaczego przy przekazywaniu map i slice do funkcji ich zmiany wewnątrz funkcji odzwierciedlają się na "oryginale"?
Odpowiedź: Ponieważ kopiowana jest tylko struktura wskaźnika, a same dane pozostają wspólne – wszelkie zmiany dotyczą tego samego bloku pamięci.
Historia
W projekcie fintech przekazywano map z ustawieniami konfiguracyjnymi do różnych serwisów, zakładając, że lokalne zmiany nie wpłyną na ogólny map. W rezultacie jeden serwis zmienił wartości, co spowodowało błędy w innych modułach, które otrzymały niespodziewanie zmienioną konfigurację.
Historia
W mikroserwisie analitycznym przekazywano slice, zakładając, że otrzymają niezależne kopie. Ale funkcja wewnątrz zmieniła wartości po indeksie, co doprowadziło do zniekształconych danych w raporcie, ponieważ pierwotna tablica została niespodziewanie zmieniona.
Historia
Na serwerach gier używano map do przechowywania sesji użytkowników i jednocześnie przekazywano tę map do kilku gorutyn. Zakładano, że każda gorutyna pracuje z swoją kopią, ale faktycznie doszło do wyścigu danych i częściowego utracenia sesji.