Целые числа
Семейство целочисленных типов
В Go нет одного типа «число». Есть семейство с чётким размером и знаком:
| Тип | Размер | Диапазон |
|---|---|---|
int8 | 8 бит | -128 … 127 |
int16 | 16 бит | -32 768 … 32 767 |
int32 | 32 бита | -2 147 483 648 … 2 147 483 647 |
int64 | 64 бита | -9.2×10¹⁸ … 9.2×10¹⁸ |
uint8 | 8 бит | 0 … 255 |
uint16 | 16 бит | 0 … 65 535 |
uint32 | 32 бита | 0 … 4 294 967 295 |
uint64 | 64 бита | 0 … 1.8×10¹⁹ |
int | 32 или 64 бит | зависит от платформы |
uint | 32 или 64 бит | зависит от платформы |
int vs int64 — ключевое различие:
var a int = 42 // на 64-bit платформе это int64
var b int64 = 42 // всегда 64 бита, везде
// Они НЕ совместимы без явного приведения:
a = b // ОШИБКА
a = int(b) // OKКогда что использовать
int— для индексов, счётчиков, обычной арифметики. Это дефолт.int64— когда нужен гарантированный размер (сериализация, протоколы).uint8/byte— для байт, цветов (RGB), бинарных данных.int32/rune— для Unicode-символов (псевдоним).
Целочисленная арифметика
a, b := 10, 3
fmt.Println(a + b) // 13
fmt.Println(a - b) // 7
fmt.Println(a * b) // 30
fmt.Println(a / b) // 3 ← дробная часть отбрасывается!
fmt.Println(a % b) // 1 ← остаток от деленияДеление — важная ловушка
В Go / для целых всегда возвращает целое:
fmt.Println(7 / 2) // 3, не 3.5
fmt.Println(7.0 / 2) // 3.5 — float64, потому что 7.0Если нужно дробное — приводи тип явно:
a, b := 7, 2
result := float64(a) / float64(b) // 3.5Остаток от деления %
fmt.Println(10 % 3) // 1
fmt.Println(-10 % 3) // -1 ← знак совпадает со знаком делимого
fmt.Println(10 % -3) // 1Типичные применения %:
// Чётность
if n % 2 == 0 { fmt.Println("чётное") }
// Циклический индекс (карусель)
next := (current + 1) % len(items)Переполнение (overflow)
Go не паникует при переполнении целых чисел в рантайме. Число просто «оборачивается»:
var x int8 = 127
x++
fmt.Println(x) // -128 (!!)Это поведение определено стандартом и предсказуемо. Но рассчитывать на него в логике — плохая идея.
Как защититься:
import "math"
func safeAdd(a, b int32) (int32, error) {
if b > 0 && a > math.MaxInt32 - b {
return 0, fmt.Errorf("overflow")
}
return a + b, nil
}Для больших чисел — пакет math/big:
import "math/big"
a := big.NewInt(9223372036854775807)
b := big.NewInt(1)
a.Add(a, b)
fmt.Println(a) // 9223372036854775808 — без переполненияБитовые операции
Целые числа — это биты в памяти. Go даёт прямой доступ к ним:
a := 0b1010 // 10 в двоичной
b := 0b1100 // 12 в двоичной
fmt.Println(a & b) // 0b1000 = 8 (AND: 1 если оба = 1)
fmt.Println(a | b) // 0b1110 = 14 (OR: 1 если хоть один = 1)
fmt.Println(a ^ b) // 0b0110 = 6 (XOR: 1 если различаются)
fmt.Println(a << 2) // 40 (сдвиг влево = ×4)
fmt.Println(a >> 1) // 5 (сдвиг вправо = ÷2)Практичное применение битовых операций
Флаги прав доступа (как в Unix):
const (
Read = 1 << iota // 1 = 0b001
Write // 2 = 0b010
Execute // 4 = 0b100
)
perms := Read | Write // 3 = 0b011
if perms & Read != 0 { fmt.Println("можно читать") }
if perms & Execute == 0 { fmt.Println("нельзя выполнять") }Быстрые операции:
// Проверка чётности (быстрее, чем %)
if n & 1 == 0 { fmt.Println("чётное") }
// Умножение/деление на степень 2
x := 5
fmt.Println(x << 3) // x * 8 = 40
fmt.Println(x >> 1) // x / 2 = 2Литералы и удобный синтаксис
Go 1.13+ поддерживает разные форматы записи чисел:
dec := 1000000 // десятичный
dec2 := 1_000_000 // с разделителями для читаемости — то же самое!
hex := 0xFF // 255 в hex
oct := 0o77 // 63 в octal
bin := 0b11001010 // 202 в binaryРазделитель _ можно ставить где угодно:
const MaxFileSize = 1_073_741_824 // 1 GiB — читается как число
const IPv6 = 0xFE80_0000_0000_0000 // удобно для hexПриведение типов
В Go нет неявного приведения. Нельзя сложить int32 и int64 без явного каста:
var a int32 = 100
var b int64 = 200
// sum := a + b // ОШИБКА: mismatched types
sum := int64(a) + b // OK
// Осторожно с усечением:
var big int64 = 1_000_000_000_000
small := int8(big) // -1 — данные потеряны!Компилятор не предупреждает о потере данных при приведении — только ты сам должен следить.
В следующем уроке разберём строки и руны — как Go работает с Unicode и почему len(s) не равно числу символов.
a, b := 10, 3
result := a + b
// result = 13