Go nigdy nie konwertuje typów niejawnie. Między zgodnymi typami konwertujesz przez T(v), a między liczbami i tekstem przez pakiet strconv. Dwie najczęściej wyszukiwane konwersje:
strconv.Itoa („integer to ASCII”) formatuje int jako tekst dziesiętny. strconv.Atoi („ASCII to integer”) parsuje tekst na int i zwraca błąd, gdy tekst nie jest poprawną liczbą. Zawsze sprawdzaj ten błąd.
Konwersja T(v)
Składnia konwersji w Go wygląda jak wywołanie funkcji nazwanej tak jak typ docelowy. Działa w trzech sytuacjach:
- między typami liczbowymi (
int,int64,float64,uint8, ...), - między
stringa[]bytelub[]rune, - między typami, które mają wspólny typ bazowy (
Celsiusifloat64).
Przyjrzyj się wynikom:
int(3.9)to3, aint(-3.9)to-3. Konwersja obcina w stronę zera; nie zaokrągla. Aby wybrać zachowanie, najpierw użyjmath.Round,math.Floorlubmath.Ceil.math.Roundzaokrągla połówki od zera, więc-3.5staje się-4.uint8(300)to44, bo zostaje tylko 8 najmłodszych bitów (300 minus 256), aint8(200)to-56z tego samego powodu. Bez błędu i bez panic.Celsiusifloat64mają wspólny typ bazowy, więc konwertują się swobodnie, ale tylko jawnie.
Wartości są celowo w zmiennych. Ze stałymi te same konwersje się nie kompilują.
Stałe są sprawdzane, zmienne nie
Konwersja stałej, która się nie mieści, to błąd kompilacji. Konwersja zmiennej o tej samej wartości po cichu zawija wartość:
fmt.Println(uint8(300)) // compile error
x := 300
fmt.Println(uint8(x)) // 44
./main.go:6:20: constant 300 overflows uint8
Konwersja stałej niecałkowitej na typ całkowity też jest odrzucana, a ta sama wartość w zmiennej jest obcinana:
./main.go:7:18: cannot convert -3.9 (untyped float constant) to type int
Jeśli liczba zmiennoprzecinkowa jest poza zakresem docelowego typu całkowitego (na przykład int64(1e20)), wynik zależy od implementacji: na przykład amd64 i arm64 dają różne odpowiedzi. Sprawdzaj zakres przed konwersją niezaufanych wartości.
Konwersja liczb na stringi
| Z | Funkcja | Przykład | Wynik |
|---|---|---|---|
int | strconv.Itoa(n) | strconv.Itoa(-7) | "-7" |
int64 | strconv.FormatInt(n, base) | strconv.FormatInt(255, 16) | "ff" |
uint64 | strconv.FormatUint(n, base) | strconv.FormatUint(5, 2) | "101" |
float64 | strconv.FormatFloat(f, fmt, prec, 64) | strconv.FormatFloat(3.14159, 'f', 2, 64) | "3.14" |
bool | strconv.FormatBool(b) | strconv.FormatBool(true) | "true" |
| cokolwiek | fmt.Sprint(v) | fmt.Sprint(3.5) | "3.5" |
| cokolwiek, sformatowane | fmt.Sprintf(format, v) | fmt.Sprintf("%05d", 42) | "00042" |
FormatFloat przyjmuje bajt formatu ('f' dla stałego przecinka, 'e' dla wykładnika, 'g' dla krótszej z tych form), precyzję (-1 oznacza „najmniej cyfr, które pozwalają dokładnie odtworzyć wartość”) i rozmiar w bitach oryginalnej liczby (64 lub 32).
strconv jest szybszy niż fmt.Sprint, który opakowuje wartość w interfejs i przechodzi przez ogólną ścieżkę formatowania fmt. W gorącej pętli ta różnica jest widoczna; przy sporadycznych konwersjach wybierz to, co czyta się lepiej.
Konwersja stringów na liczby
| Na | Funkcja | Zwraca |
|---|---|---|
int | strconv.Atoi(s) | int, error |
| dowolny int ze znakiem | strconv.ParseInt(s, base, bitSize) | int64, error |
| dowolny int bez znaku | strconv.ParseUint(s, base, bitSize) | uint64, error |
| float | strconv.ParseFloat(s, bitSize) | float64, error |
| bool | strconv.ParseBool(s) | bool, error |
ParseInt zawsze zwraca int64. Argument bitSize (0, 8, 16, 32, 64) ustala akceptowany zakres, więc wynik na pewno się zmieści, gdy przekonwertujesz go na mniejszy typ. base 0 oznacza „wywnioskuj z prefiksu”, więc 0x1f, 0o17, 0b101 i 1_000 są parsowane.
Co pokazuje wynik:
" 42"się nie parsuje.Atoiakceptuje opcjonalny znak i cyfry, nic więcej. Dane zbufiozwykle kończą się na\n, więc je przytnij."4.2"jest niepoprawne dlaAtoi. Do liczb dziesiętnych użyjParseFloat.- Przy błędzie przekroczenia zakresu
ParseIntzwraca największą wartość, która się mieści (127dlaint8), razem z błędem. Nie używaj tej wartości, gdy błąd nie jest nil. - Błędy to wartości
*strconv.NumErroropakowującestrconv.ErrSyntaxlubstrconv.ErrRange, więcerrors.Ispotrafi je odróżnić.
ParseBool akceptuje 1, t, T, TRUE, true, True i odpowiadające im formy dla fałszu. "yes" i "on" to błędy.
Pułapka string(65)
Konwersja liczby całkowitej na string nie daje cyfr. Daje znak o tym punkcie kodowym Unicode:
n := 65
s := string(n) // "A", not "65"
Kompilator to akceptuje, ale go vet to zgłasza:
./main.go:10:7: conversion from int to string yields a string of one rune, not a string of digits
Jeśli naprawdę chcesz znak, powiedz to wprost przez runę: string(rune(n)). Jeśli chcesz liczbę jako tekst, użyj strconv.Itoa(n). Konwersja rune lub byte na string jest poprawna i częsta:
Stringi, bajty i rune
string, []byte i []rune konwertują się między sobą przez T(v). Każda konwersja kopiuje dane, bo stringi są niezmienne, a slice'y nie:
Konwertuj na []rune, gdy musisz indeksować lub modyfikować po znakach; konwertuj na []byte do wejścia i wyjścia, hashowania i edycji na poziomie bajtów. Strona o runach i bajtach szczegółowo omawia UTF-8.
Konwersja a asercja typu
Konwersja zmienia wartość z jednego typu konkretnego na inny. Wydobycie konkretnej wartości z interfejsu (any, error, io.Reader) to inna operacja, asercja typu:
var v any = 42
n := v.(int) // type assertion: v holds an int, give it to me
f := float64(n) // conversion: int to float64
// f := float64(v) // compile error: cannot convert v (variable of interface type any)
// // to type float64: need type assertion
Najpierw asercja, potem konwersja. Forma comma-ok n, ok := v.(int) pozwala uniknąć panic, gdy typ jest zły.
Ściągawka
| Zadanie | Kod |
|---|---|
| int na string | strconv.Itoa(n) |
| int64 na string | strconv.FormatInt(n, 10) |
| string na int | n, err := strconv.Atoi(s) |
| string na int64 | n, err := strconv.ParseInt(s, 10, 64) |
| string na float64 | f, err := strconv.ParseFloat(s, 64) |
| float64 na string | strconv.FormatFloat(f, 'f', -1, 64) |
| float64 na int | int(f) (obcina) lub int(math.Round(f)) |
| int na float64 | float64(n) |
| string na []byte | []byte(s) |
| []byte na string | string(b) |
| rune na string | string(r) |
| bool na string | strconv.FormatBool(b) |
| dowolna wartość na string | fmt.Sprint(v) |
Najczęściej zadawane pytania
Jak zamienić int na string w Go?
Użyj strconv.Itoa(n): strconv.Itoa(42) zwraca "42". Dla int64 użyj strconv.FormatInt(n, 10). fmt.Sprint(n) też działa dla każdego typu, ale jest wolniejsze. Nie pisz string(n): to traktuje n jako punkt kodowy Unicode, więc string(65) to "A".
Jak zamienić string na int w Go?
Użyj strconv.Atoi, która zwraca liczbę i błąd:
n, err := strconv.Atoi("42")
if err != nil {
// not a valid integer
}
Dla konkretnego rozmiaru lub podstawy użyj strconv.ParseInt(s, 10, 64), która zwraca int64. Atoi nie usuwa spacji, więc " 42" daje błąd; najpierw wywołaj strings.TrimSpace.
Jak zrobić rzutowanie (cast) w Go?
Go nazywa to konwersją, a składnia to T(v): float64(n), int(f), []byte(s). Działa między typami liczbowymi, między stringami a slice'ami bajtów lub run oraz między typami o tym samym typie bazowym. Nie parsuje tekstu: zamiana "42" na 42 wymaga strconv. Wydobycie konkretnego typu z interfejsu to asercja typu, v.(T), a nie konwersja.
Jak zamienić float na int w Go?
int(f) obcina w stronę zera: int(3.9) to 3, a int(-3.9) to -3. Aby zaokrąglić, użyj int(math.Round(f)). Jeśli liczba zmiennoprzecinkowa jest poza zakresem typu całkowitego, wynik zależy od implementacji, więc gdy wartość pochodzi z wejścia, najpierw sprawdź zakres.
Dlaczego string(65) zwraca "A" w Go?
Konwersja liczby całkowitej na string interpretuje ją jako punkt kodowy Unicode, a 65 to punkt kodowy A. go vet to zgłasza: conversion from int to string yields a string of one rune, not a string of digits. Użyj strconv.Itoa(65), aby dostać "65".