В чём разница между int, int32 и int64?
Краткий ответ
| Тип | Размер | Диапазон значений |
|---|---|---|
int32 | всегда 4 байта (32 бита) | от -2 147 483 648 до 2 147 483 647 |
int64 | всегда 8 байт (64 бита) | от -9.2·10¹⁸ до 9.2·10¹⁸ |
int | зависит от платформы: 4 байта на 32-битных системах, 8 байт на 64-битных | соответственно |
Главные различия — размер в памяти, диапазон значений и переносимость между платформами.
Что значит «32 бита» и «64 бита»
Бит — это одна ячейка памяти, которая хранит 0 или 1. Чем больше битов мы выделяем под число, тем больше различных чисел оно может представлять.
- 32 бита = 4 байта = 2³² ≈ 4.3 миллиарда различных значений
- 64 бита = 8 байт = 2⁶⁴ ≈ 1.8·10¹⁹ различных значений
Поскольку числа со знаком (могут быть отрицательными), один бит уходит на знак, и диапазон делится примерно пополам — половина под отрицательные, половина под положительные.
// int32: 4 миллиарда / 2 ≈ 2.1 миллиарда в каждую сторону
// int64: 1.8·10¹⁹ / 2 ≈ 9.2·10¹⁸ в каждую сторонуint32 и int64 — фиксированный размер
Эти типы гарантированно имеют свой размер на любой платформе. Это важно, когда:
- ты работаешь с двоичными форматами (файлы, сетевые протоколы)
- сериализуешь данные в БД
- делаешь обмен данными между разными системами
var a int32 = 100
var b int64 = 100
fmt.Println(unsafe.Sizeof(a)) // 4 (всегда)
fmt.Println(unsafe.Sizeof(b)) // 8 (всегда)unsafe.Sizeof — встроенная функция, возвращающая размер значения в байтах.
int — размер зависит от платформы
Тип int — это «удобный целочисленный тип по умолчанию», его размер выбирает компилятор в зависимости от того, на какую систему ты компилируешь программу:
- На 64-битной системе (любой современный сервер, ноутбук) —
int= 64 бита (какint64) - На 32-битной системе (старое железо, микроконтроллеры) —
int= 32 бита (какint32)
var x int = 42
fmt.Println(unsafe.Sizeof(x)) // на твоей машине почти наверняка 8⚠️ Несмотря на то, что на 64-битной системе int и int64 имеют одинаковый размер, это разные типы для компилятора. Между ними нельзя присваивать без явного преобразования:
var a int = 10
var b int64 = a // ❌ ошибка компиляции: cannot use a (type int) as type int64
var b int64 = int64(a) // ✅ нужно явное преобразованиеЧто произойдёт при выходе за диапазон
Если попытаться положить в число значение больше максимума, происходит переполнение (overflow) — число «оборачивается» через минимум.
var x int32 = 2147483647 // максимум для int32
x++
fmt.Println(x) // -2147483648 — стало минимумом!Go не выбрасывает ошибку при переполнении в рантайме (для производительности). Это нужно учитывать.
Какой тип выбирать на практике
По умолчанию используй int
Это идиоматичный (общепринятый) выбор для Go. Для счётчиков, индексов, размеров коллекций — всегда int.
for i := 0; i < len(slice); i++ { // i и len() возвращают int
...
}
count := 0 // тоже intСтандартная библиотека Go повсеместно использует int: len(), cap(), индексы слайсов и мап — всё int.
Используй int64, когда...
1. Числа могут быть очень большими
var fileSize int64 // размер файла может быть > 2 ГБ
var unixTimestamp int64 // время в наносекундах с 1970
var population int64 // население Земли > 2.1 млрд2. Работаешь с базой данных
В SQL поля типа BIGINT маппятся на int64. ID часто хранят как int64:
type User struct {
ID int64 // соответствует BIGINT в БД
}3. Считаешь деньги в копейках/центах
Чтобы избежать ошибок с плавающей точкой, деньги хранят как целые числа в минимальной единице:
var balance int64 // в копейках. 100 копеек = 1 рубль
// позволяет хранить до ~92 квадриллионов копеек4. Нужна гарантия размера на любой платформе
Например, для протокола обмена с другой системой.
Используй int32, когда...
1. Экономишь память в больших массивах
Если у тебя 100 миллионов чисел и они все маленькие — int32 занимает в 2 раза меньше памяти, чем int64.
ids := make([]int32, 100_000_000) // 400 МБ вместо 800 МБ2. Сериализация в форматы с фиксированным размером
Например, бинарные сетевые протоколы, где явно указано «здесь идёт 4-байтовое целое».
3. Работа с внешними API
Многие протоколы (Protocol Buffers, gRPC) различают int32 и int64. Если в .proto-файле написано int32, то и в Go должен быть int32.
Преобразования между типами
В Go нет неявных преобразований между числовыми типами — даже если они разной разрядности. Всегда нужно писать явно:
var a int = 100
var b int64 = int64(a) // явное преобразование
var c int32 = int32(b) // тоже явное
// Опасный случай — преобразование "сверху вниз"
var big int64 = 5_000_000_000 // не помещается в int32
var small int32 = int32(big) // обрезается! значение испортится
fmt.Println(small) // 705032704 — мусорСравнение по типам — тоже строгое
Нельзя сравнивать переменные разных целочисленных типов напрямую:
var a int = 5
var b int32 = 5
fmt.Println(a == b) // ❌ ошибка: mismatched types int and int32
fmt.Println(a == int(b)) // ✅ trueРеальный пример: работа с временем
import "time"
t := time.Now()
// Unix timestamp — секунды с 1970 года
sec := t.Unix() // возвращает int64
fmt.Println(sec) // например, 1714298400
// Если попробовать положить в int32 — на ~2038 год значение перестанет помещаться
// (это известная "проблема 2038 года" в системах, где timestamp хранится как int32)Реальный пример: размер файла
import "os"
info, _ := os.Stat("video.mp4")
size := info.Size() // возвращает int64
// потому что файл может быть > 4 ГБ
if size > 1024*1024*1024 {
fmt.Println("Большой файл")
}Если бы Size() возвращал int32, библиотека не могла бы корректно обрабатывать файлы больше 2 ГБ.
Краткое резюме
| Сценарий | Что использовать |
|---|---|
| Счётчики, индексы, размеры, общие задачи | int (по умолчанию) |
| Размеры файлов, timestamps, ID в БД, деньги | int64 |
| Большие массивы маленьких чисел, бинарные протоколы | int32 |
| Гарантия размера независимо от платформы | int32 или int64 (никогда int) |
Главное правило: если не уверен — используй int. Это идиоматично, эффективно на современных машинах и достаточно для большинства задач.