Wartości
Często spotykam się z tym, że programiści utożsamiają zmienną z jej zawartością. A jest to gruba nieprawda: zmienna to tylko nazwa (identyfikator) dzięki której możemy się odwołać do konkretnej wartości (która jest trzymana gdzieś w pamięci). Na przykładach:
a := "wartość"
Zmienna a wskazuje na wartość którą jest ciąg znaków "wartość". To że nie
ma zmiennej wskazującej na jakąś wartość nie oznacza, że nie mamy takiej wartości
zapisanej w pamięci, choć jest to mocna wskazówka dla garbage collectora, by
taka pamięć zwolnić. Zmienna określonego typu może przechowywać tylko wartości
które są "przypisywalne" do tego typu.
Sposoby tworzenia wartości
Są trzy podstawowe sposoby tworzenia wartości (a co za tym idzie alokowania pamięci)
- zastosowanie wbudowanej funkcji new()
- zastosowanie wbudowanej funkcji make()
- zastosowanie literału
Napisałem "podstawowe", a to dlatego, że gdy operujemy na slice możemy "przez
przypadek" utworzyć całkiem nową wartość. Dokładniej zgłębimy temat w artykule
o wycinkach.
Wszystkie się od siebie różnią dlatego omówimy je osobno.
new()
To nietypowa funkcja dla Go, bo jako argument przyjmuje typ, a nie wartość, a co gorsza zwraca nową wartość ale innego typu niż jej przekazaliśmy :-)
A tak na poważnie: funkcja new zajmuje się alokowaniem pamięci dla
wartości, której typ został przekazany w wywołaniu i zwraca wskaźnik do niej.
W kodzie wygląda to tak:
type point struct { a int b int } var p *point p = new(point)
Zauważ, że zadeklarowaliśmy p jako wskaźnik do wartości typu T.
Funkcja new inicjalizuje wartość na tak zwane zero typu, czyli jeśli typem
był struct to wszystkie pola tej struktury zostaną wyzerowane; a jeśli typem
jest int to zwróci wskaźnik do nowo utworzonej wartości zero.
Właśnie ze względu na tę ostatnią cechę nie używamy new dla typów referencyjnych:
map, slice, chan, bo zerem dla typu referencyjnego jest nil zmienna wskazująca
na nil nie jest zbyt użyteczna :-)
make()
Dla typów referencyjnych tj. map, slice i chan została stworzona inna funkcja:
make, której oprócz typu przekazujemy początkowe właściwości:
-
dla
sliceto będzie długość (len) i pojemność (cap), przy czym pojemność jest opcjonalna:sli := make([]int, len, cap) sli2 := make([]int, len)
-
dla
mapto wstępna ilość elementów (cap), opcjonalnam := make(map[int]string, cap) m1 := make(map[int]string)
-
dla
chanmożemy określić wielkość bufora elementów (len)ch := make(chan int, len)//kanał z buforem ch1 := make(chan int)//kanał bez bufora
make zwraca wartość zgodną z typem przekazanym w wywołaniu.
Literały
Ze względu na objętość omówienie literałów wyłączyłem do osobnego artykułu.
Wszystko o języku programowania Go