Menu

Golang: int в string, string в int и преобразование типов

Как преобразовывать типы в Go: int в string и string в int через strconv, float в int, числовые преобразования через T(v), байты и руны, ловушка string(65) и обработка ошибок преобразования.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Go никогда не преобразует типы неявно. Между совместимыми типами вы преобразуете через T(v), а между числами и текстом через пакет strconv. Два самых популярных в поиске преобразования:

strconv.Itoa («integer to ASCII») форматирует int как десятичный текст. strconv.Atoi («ASCII to integer») разбирает текст в int и возвращает ошибку, если текст не является корректным числом. Всегда проверяйте эту ошибку.

Преобразование T(v)

Синтаксис преобразования в Go похож на вызов функции с именем целевого типа. Он работает в трёх случаях:

  1. между числовыми типами (int, int64, float64, uint8, ...),
  2. между string и []byte или []rune,
  3. между типами с общим базовым типом (Celsius и float64).

Посмотрите на результаты внимательно:

  • int(3.9) равно 3, а int(-3.9) равно -3. Преобразование отбрасывает дробную часть в сторону нуля, а не округляет. Чтобы выбрать поведение, сначала примените math.Round, math.Floor или math.Ceil. math.Round округляет половину от нуля, поэтому -3.5 становится -4.
  • uint8(300) равно 44, потому что остаются только младшие 8 бит (300 минус 256), а int8(200) по той же причине равно -56. Ни ошибки, ни паники.
  • У Celsius и float64 общий базовый тип, поэтому они свободно преобразуются друг в друга, но только явно.

Значения намеренно лежат в переменных. С константами те же преобразования не скомпилируются.

Константы проверяются, переменные нет

Преобразование константы, которая не помещается в тип, это ошибка компиляции. Преобразование переменной с тем же значением молча заворачивается:

fmt.Println(uint8(300)) // compile error
x := 300
fmt.Println(uint8(x)) // 44
./main.go:6:20: constant 300 overflows uint8

Преобразование нецелой константы в целочисленный тип тоже отвергается, а то же значение в переменной просто усекается:

./main.go:7:18: cannot convert -3.9 (untyped float constant) to type int

Если значение float выходит за диапазон целевого целочисленного типа (скажем, int64(1e20)), результат зависит от реализации: например, amd64 и arm64 дают разные ответы. Проверяйте диапазон, прежде чем преобразовывать непроверенные значения.

Преобразование чисел в строки

ИзФункцияПримерРезультат
intstrconv.Itoa(n)strconv.Itoa(-7)"-7"
int64strconv.FormatInt(n, base)strconv.FormatInt(255, 16)"ff"
uint64strconv.FormatUint(n, base)strconv.FormatUint(5, 2)"101"
float64strconv.FormatFloat(f, fmt, prec, 64)strconv.FormatFloat(3.14159, 'f', 2, 64)"3.14"
boolstrconv.FormatBool(b)strconv.FormatBool(true)"true"
что угодноfmt.Sprint(v)fmt.Sprint(3.5)"3.5"
что угодно, с форматомfmt.Sprintf(format, v)fmt.Sprintf("%05d", 42)"00042"

FormatFloat принимает байт формата ('f' для фиксированной записи, 'e' для экспоненциальной, 'g' для той, что короче), точность (-1 означает «наименьшее число цифр, которое точно восстанавливает значение») и разрядность исходного float (64 или 32).

strconv быстрее, чем fmt.Sprint, который упаковывает значение в интерфейс и проходит через общий путь форматирования fmt. В горячем цикле разница заметна; для редких преобразований выбирайте то, что лучше читается.

Преобразование строк в числа

Во чтоФункцияВозвращает
intstrconv.Atoi(s)int, error
любое знаковое целоеstrconv.ParseInt(s, base, bitSize)int64, error
любое беззнаковое целоеstrconv.ParseUint(s, base, bitSize)uint64, error
floatstrconv.ParseFloat(s, bitSize)float64, error
boolstrconv.ParseBool(s)bool, error

ParseInt всегда возвращает int64. Аргумент bitSize (0, 8, 16, 32, 64) задаёт допустимый диапазон, так что результат гарантированно поместится, когда вы преобразуете его в меньший тип. base 0 означает «определить по префиксу», поэтому разбираются 0x1f, 0o17, 0b101 и 1_000.

Что показывает вывод:

  • " 42" не разбирается. Atoi принимает необязательный знак и цифры, больше ничего. Ввод из bufio обычно заканчивается на \n, поэтому обрезайте его.
  • "4.2" для Atoi некорректно. Для дробных чисел используйте ParseFloat.
  • При ошибке выхода за диапазон ParseInt возвращает наибольшее значение, которое помещается (127 для int8), вместе с ошибкой. Не используйте значение, если ошибка не nil.
  • Ошибки имеют тип *strconv.NumError и оборачивают strconv.ErrSyntax или strconv.ErrRange, поэтому errors.Is может их различить.

ParseBool принимает 1, t, T, TRUE, true, True и соответствующие формы false. "yes" и "on" дают ошибку.

Ловушка string(65)

Преобразование целого числа в string не даёт цифры. Оно даёт символ с этой кодовой точкой Unicode:

n := 65
s := string(n) // "A", not "65"

Компилятор это пропускает, но go vet сообщает:

./main.go:10:7: conversion from int to string yields a string of one rune, not a string of digits

Если вам действительно нужен символ, скажите это явно через руну: string(rune(n)). Если нужно число в виде текста, используйте strconv.Itoa(n). Преобразовать rune или byte в string можно, и это обычное дело:

Строки, байты и руны

string, []byte и []rune преобразуются друг в друга через T(v). Каждое преобразование копирует данные, потому что строки неизменяемы, а слайсы нет:

Преобразуйте в []rune, когда нужно индексировать или изменять по символам; в []byte для ввода-вывода, хеширования и правок на уровне байтов. UTF-8 подробно разобран на странице о рунах и байтах.

Преобразование и утверждение типа

Преобразование меняет значение одного конкретного типа на другой. Достать конкретное значение из интерфейса (any, error, io.Reader) это другая операция, утверждение типа (type assertion):

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

Сначала утверждение, затем преобразование. Форма comma-ok n, ok := v.(int) позволяет избежать паники, если тип не тот.

Шпаргалка

ЗадачаКод
int в stringstrconv.Itoa(n)
int64 в stringstrconv.FormatInt(n, 10)
string в intn, err := strconv.Atoi(s)
string в int64n, err := strconv.ParseInt(s, 10, 64)
string в float64f, err := strconv.ParseFloat(s, 64)
float64 в stringstrconv.FormatFloat(f, 'f', -1, 64)
float64 в intint(f) (отбрасывает дробь) или int(math.Round(f))
int в float64float64(n)
string в []byte[]byte(s)
[]byte в stringstring(b)
rune в stringstring(r)
bool в stringstrconv.FormatBool(b)
любое значение в stringfmt.Sprint(v)

Часто задаваемые вопросы

Как преобразовать int в string в Go?

Используйте strconv.Itoa(n): strconv.Itoa(42) возвращает "42". Для int64 подойдёт strconv.FormatInt(n, 10). fmt.Sprint(n) тоже работает с любым типом, но медленнее. Не пишите string(n): так n трактуется как кодовая точка Unicode, и string(65) равно "A".

Как преобразовать string в int в Go?

Используйте strconv.Atoi, которая возвращает число и ошибку:

n, err := strconv.Atoi("42")
if err != nil {
	// not a valid integer
}

Для конкретного размера или системы счисления используйте strconv.ParseInt(s, 10, 64), она возвращает int64. Atoi не обрезает пробелы, поэтому " 42" даёт ошибку; сначала вызовите strings.TrimSpace.

Как сделать приведение типов (cast) в Go?

В Go это называется преобразованием, синтаксис T(v): float64(n), int(f), []byte(s). Оно работает между числовыми типами, между строками и слайсами байтов или рун, а также между типами с одинаковым базовым типом. Разбирать текст оно не умеет: чтобы превратить "42" в 42, нужен strconv. Достать конкретный тип из интерфейса можно утверждением типа v.(T), а не преобразованием.

Как преобразовать float в int в Go?

int(f) отбрасывает дробную часть в сторону нуля: int(3.9) равно 3, а int(-3.9) равно -3. Для округления используйте int(math.Round(f)). Если float выходит за диапазон целочисленного типа, результат зависит от реализации, поэтому проверяйте диапазон, когда значение приходит из ввода.

Почему string(65) возвращает "A" в Go?

Преобразование целого числа в string трактует его как кодовую точку Unicode, а 65 это кодовая точка A. go vet это отмечает: conversion from int to string yields a string of one rune, not a string of digits. Чтобы получить "65", используйте strconv.Itoa(65).

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ