programowanieProgramista Go

Wyjaśnij cechy działania wbudowanej funkcji make w Go: kiedy jest ona konieczna, jak działa inicjalizacja cięcia dla map, slice i channel? Jakie błędy występują z powodu niewłaściwego użycia make i new?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Funkcja make w Go jest używana wyłącznie do inicjalizacji obiektów typów: slice, map i channel. Przydziela ona odpowiednią strukturę danych i zwraca gotowy do użycia obiekt (nie wskaźnik!).

Przykłady:

s := make([]int, 5, 10) // slice o długości 5, pojemności 10 m := make(map[string]int) // pusty map ch := make(chan int, 2) // buforowany kanał na 2

Szczegóły:

  • Dla slice parametry: długość (len) i (opcjonalnie) pojemność (cap).
  • Dla map i chan — tylko (opcjonalna) pojemność (początkowy rozmiar/bufor).
  • Funkcja make zwraca już zainicjalizowany obiekt, gotowy do użycia.
  • Dla innych typów (struct, array) make nie jest używana, inicjalizuje się je za pomocą literałów lub new (która zwraca wskaźnik na zero value).

Porównanie z new:

  • new(T) zwraca *T, gdzie wszystkie pola są zerowe.
  • make(T) zwraca T tylko dla trzech typów: slice, map, chan.

Pytanie z pułapką

Czy można uzyskać działający map przez new zamiast make?

m := new(map[string]int) (*m)["a"] = 1 // Co się stanie?

Wielu uważa, że to poprawne, ale wystąpi panic w czasie działania: assignment to entry in nil map. Ponieważ w zmiennej *m jest nil!

Poprawnie: używać make:

m := make(map[string]int) m["a"] = 1 // OK

Przykłady rzeczywistych błędów z powodu niewiedzy na temat szczegółów


Historia

W mikroserwisie do przechowywania pamięci podręcznej stworzono mapę przez var cache map[string]interface{} bez inicjalizacji make, co spowodowało panic przy zapisywaniu w produkcji z niezrozumiałymi stack trace. Problem został znaleziony dopiero po analizie kodu: mapa była nil.


Historia

Podczas pisania potoku danych zapomniano o buforze w kanale i stworzono przez make(chan int). W rezultacie, gorutyny utknęły, czekając na odczyt, chociaż oczekiwano asynchronicznej wymiany. Błąd zauważono dopiero podczas testów skalowania.


Historia

W projekcie, gdzie inicjalizacja odbywała się przez new, niektórzy programiści próbowali używać new([]int) zamiast make([]int, 10), w rezultacie otrzymali wskaźnik na nil slice i panic w czasie działania przy pierwszych próbach zapisu.