Podstawowe typy Go to liczby, wartości logiczne i stringi. Każda zmienna ma dokładnie jeden typ, ustalony w czasie kompilacji, a Go nigdy nie konwertuje typów za ciebie. %T wypisuje typ dowolnej wartości:
Zwróć uwagę, że 'G' wypisuje się jako 71 z typem int32: znak w apostrofach to runa, czyli liczba (punkt kodowy Unicode). rune to alias int32 (ten sam typ pod drugą nazwą), więc %T zgłasza int32. Podobnie byte zgłasza uint8.
Liczby całkowite
| Typ | Rozmiar | Zakres |
|---|---|---|
int8 | 8 bitów | od -128 do 127 |
int16 | 16 bitów | od -32 768 do 32 767 |
int32 | 32 bity | od około -2,1 miliarda do 2,1 miliarda |
int64 | 64 bity | od około -9,2 tryliona do 9,2 tryliona |
uint8 (byte) | 8 bitów | od 0 do 255 |
uint16 | 16 bitów | od 0 do 65 535 |
uint32 | 32 bity | od 0 do około 4,3 miliarda |
uint64 | 64 bity | od 0 do około 18,4 tryliona |
int, uint | 32 lub 64 bity | rozmiar słowa platformy |
uintptr | rozmiar platformy | przechowuje wartość wskaźnika, do kodu niskopoziomowego |
Domyślnie używaj int. len() zwraca int, indeksy slice'ów to int i liczniki pętli to int. Na każdej platformie 64-bitowej int ma 64 bity. Po typy o określonym rozmiarze sięgaj wtedy, gdy rozmiar jest częścią umowy: int32 w binarnym formacie pliku, uint8 dla surowych bajtów, int64 dla znacznika czasu Unix w nanosekundach.
Unikaj typów bez znaku dla wielkości, które "nie mogą być ujemne", takich jak liczniki. Odejmowanie poniżej zera zawija się do ogromnej liczby, zamiast dać wartość ujemną, którą dałoby się wyłapać.
Limity i przepełnienie
Pakiet math ma stałą dla każdego limitu. W czasie działania arytmetyka całkowita, która się przepełnia, po cichu się zawija:
Bez panic, bez błędu: 127 + 1 staje się -128. W czasie kompilacji sprawdzane są tylko wyrażenia stałe (var b int8 = 128 się nie kompiluje). Jeśli w twoich danych możliwe jest przepełnienie, sprawdzaj przed operacją albo użyj math/big.
Literały całkowite
million := 1_000_000 // underscores for readability (Go 1.13+)
mask := 0xFF // hexadecimal
perm := 0o755 // octal (also the older form 0755)
flags := 0b1010 // binary
Liczby zmiennoprzecinkowe
| Typ | Rozmiar | Precyzja |
|---|---|---|
float32 | 32 bity | około 6 do 9 cyfr znaczących |
float64 | 64 bity | około 15 do 17 cyfr znaczących |
Literał z kropką dziesiętną lub wykładnikiem (2.5, 1e6) jest domyślnie typu float64, a pakiet math przyjmuje i zwraca float64. Używaj go, chyba że liczy się pamięć w dużej tablicy.
Liczby zmiennoprzecinkowe są binarne, więc większość ułamków dziesiętnych to przybliżenia:
Wynikają z tego dwie zasady. Nigdy nie porównuj floatów przez == po obliczeniach. I nigdy nie przechowuj pieniędzy we floatach: użyj liczby całkowitej groszy albo biblioteki liczb dziesiętnych.
Dzielenie floata przez zero daje +Inf, -Inf lub NaN zamiast panic. Dzielenie liczby całkowitej przez zero wywołuje panic w czasie działania (runtime error: integer divide by zero), a stały dzielnik równy zero to błąd kompilacji.
Wartości logiczne
bool przechowuje true lub false, a jego wartość zerowa to false. Go nie traktuje liczb, pustych stringów ani nil jako wartości logicznych. if count {} to błąd kompilacji; napisz if count > 0 {}. Operatory to &&, || i !, przy czym && i || działają skrótowo.
Stringi
string to niezmienny ciąg bajtów, zwykle tekst w UTF-8. len(s) liczy bajty, nie znaki:
é zajmuje w UTF-8 dwa bajty, więc len zgłasza 6 dla pięciu znaków. Stringi w cudzysłowach przetwarzają sekwencje ucieczki, takie jak \n; surowe stringi w odwrotnych apostrofach tego nie robią i mogą obejmować wiele linii. Strona o stringach omawia pakiet strings, a strona o runach i bajtach szczegółowo opisuje UTF-8.
byte i rune
| Alias | To samo co | Przechowuje |
|---|---|---|
byte | uint8 | jeden bajt surowych danych |
rune | int32 | jeden punkt kodowy Unicode |
To aliasy, a nie nowe typy: byte i uint8 są wymienne bez konwersji. Nazwy mówią, co oznacza liczba.
Liczby zespolone
Go ma wbudowane typy zespolone, complex64 i complex128, a do tego real, imag i pakiet math/cmplx:
Potrzebuje ich niewiele programów, ale przetwarzanie sygnałów i część kodu numerycznego tak.
Typy złożone i referencyjne
Typy podstawowe łączą się w typy złożone. Każdy ma własną stronę:
| Typ | Przykład | Wartość zerowa |
|---|---|---|
| tablica | [3]int | trzy zera |
| slice | []int | nil |
| mapa | map[string]int | nil |
| struktura | struct{ X, Y int } | każde pole wyzerowane |
| wskaźnik | *int | nil |
| funkcja | func(int) int | nil |
| kanał | chan int | nil |
| interfejs | error, any | nil |
any to alias interface{} (od Go 1.18) i może przechowywać wartość dowolnego typu.
Typy nazwane
Możesz zdefiniować nowy typ na podstawie istniejącego. Ma tę samą reprezentację, ale jest odrębnym typem i może mieć metody:
type Celsius float64
type UserID int64
var t Celsius = 21.5
var f float64 = t // compile error: cannot use t (variable of float64 type Celsius) as float64 value in variable declaration
Ta surowość jest celowa: UserID nie da się przypadkiem przekazać tam, gdzie oczekiwany jest OrderID. Gdy naprawdę tego chcesz, konwertuj jawnie: float64(t). Zasady opisuje strona o konwersji typów, a do przechodzenia między liczbami i stringami służą funkcje z strconv.
Wartości zerowe
Każdy typ ma wartość zerową, czyli to, co zmienna przechowuje, zanim cokolwiek do niej przypiszesz: 0 dla liczb, false dla bool, "" dla stringów oraz nil dla wskaźników, slice'ów, map, kanałów, funkcji i interfejsów. W Go nie ma niezainicjalizowanych zmiennych.
Najczęściej zadawane pytania
Jaki rozmiar ma int w Go?
int i uint mają 64 bity na platformach 64-bitowych (amd64, arm64) i 32 bity na platformach 32-bitowych. Jeśli potrzebujesz stałego rozmiaru, na przykład dla formatu pliku lub protokołu sieciowego, użyj int32, int64, uint8 i tak dalej. Do zwykłych liczników, indeksów i długości używaj int.
Jak wypisać typ zmiennej w Go?
Użyj czasownika %T: fmt.Printf("%T\n", x) wypisuje int, float64, []string, main.User i tak dalej. W kodzie reflect.TypeOf(x) zwraca tę samą informację jako wartość, którą można badać.
Czym różni się byte od rune w Go?
byte to alias uint8 i przechowuje jeden bajt surowych danych. rune to alias int32 i przechowuje jeden punkt kodowy Unicode. String to ciąg bajtów; iterowanie po nim przez for range dekoduje go na runy.
Używać float32 czy float64 w Go?
Używaj float64, chyba że masz powód, żeby tego nie robić. To domyślny typ literałów zmiennoprzecinkowych, typ, z którym pracuje pakiet math, i ma około 15 do 17 cyfr znaczących precyzji wobec około 6 do 9 dla float32. Wybieraj float32 tylko po to, żeby zmniejszyć o połowę zużycie pamięci w dużych tablicach albo dopasować się do zewnętrznego formatu.
Jaka jest maksymalna wartość int w Go?
Użyj stałych z pakietu math: math.MaxInt (9223372036854775807 na platformach 64-bitowych), math.MinInt, math.MaxInt64, math.MaxUint32 i tak dalej. Arytmetyka, która przekracza limit, w czasie działania po cichu się zawija; nie wywołuje panic.