---
title: "Типы данных: числа"
description: "Числовые типы данных в Go: int и float64, целочисленное деление, переполнение и явные преобразования. Разбираем на примерах, которые можно запустить."
course: "Go с нуля: базовый синтаксис и конструкции"
url: "https://golangmaster.ru/courses/go-basics/lessons/05-tipy-chisel/"
published: "2026-09-19"
updated: "2026-09-28"
minutes: 20
---

# Типы данных: числа

*Курс «Go с нуля: базовый синтаксис и конструкции», урок 5 из 25. ~20 минут. Обновлено 28.09.2026. Источник: https://golangmaster.ru/courses/go-basics/lessons/05-tipy-chisel/*

Типы данных в Go устроены строже, чем кажется: у чисел дюжина разновидностей, деление двух целых отбрасывает дробную часть, а int нельзя сложить с float64 без явного преобразования. В этом уроке разберём целые и вещественные типы, узнаем, почему 7/2 — это 3, что такое переполнение и как Go заставляет вас конвертировать типы руками — и почему это, на самом деле, удобно.

### Целые числа: int и его родственники

Основной целочисленный тип в Go — int. Когда вы пишете `x := 42`, компилятор создаёт именно int, если правая часть — целое число без явного типа. На большинстве платформ это 64-битное знаковое целое с диапазоном примерно от -9,2 млрд миллионов до +9,2 млрд миллионов — для счётчиков, длин массивов и повседневной арифметики хватает с запасом.

Но int — не единственный вариант. Есть семейство фиксированных размеров: int8 (от -128 до 127), int16, int32, int64 — и их беззнаковые братья uint, uint8, uint16, uint32, uint64, которые принимают только неотрицательные значения. Зачем они нужны? Когда размер важен: uint8 (у него есть псевдоним byte) лежит в основе работы с байтами, int64 встречается в метках времени и базах данных, int32 — в протоколах обмена.

Практическое правило: по умолчанию пишите int и не думайте о размере. Явные типы берите тогда, когда формат данных диктует их — сетевой протокол, бинарный файл, стыковка с базой. Для новичка выбор «int для всего целого» — не лень, а идиома.

### Основные целочисленные типы

| Тип | Размер | Диапазон | Когда использовать |
| --- | --- | --- | --- |
| int | зависит от платформы (обычно 64 бита) | -9,2 квинтиллиона до 9,2 квинтиллиона | по умолчанию для всех целых |
| int8 | 8 бит | -128 до 127 | компактные знаковые значения |
| int32 | 32 бита | около -2,1 млрд до 2,1 млрд | протоколы, руны (rune = int32) |
| int64 | 64 бита | около ±9,2 квинтиллиона | метки времени, большие счётчики |
| uint8 (byte) | 8 бит | 0 до 255 | байты, байтовые срезы |
| uint64 | 64 бита | 0 до 18,4 квинтиллиона | хэши, битовые маски без знака |

### Дробные числа: float64 как выбор по умолчанию

Дробные числа в Go живут в двух типах: float64 и float32. Если тип не указан, `pi := 3.14` создаёт float64 — и это правильный выбор по умолчанию. float64 хранит около 15-16 значащих цифр и покрывает почти все бытовые задачи: физика, координаты, статистика. float32 экономит память (4 байта вместо 8), но даёт лишь около 7 цифр точности — его берут для больших массивов данных, графики и машинного обучения, где объём важнее точности.

Важно понимать: float — это двоичное представление дроби, а не десятичное. Числа вроде 0.1 точно не представляются, из-за чего 0.1 + 0.2 оказывается 0.30000000000000004. Это не баг Go, а свойство IEEE 754 — так работают float в любом современном языке. Именно поэтому дробные деньги в финансах хранят в целых копейках, а не во float.

Пара синтаксических мелочей: запись `3.` (три и точка) легальна и равна 3.0, а экспонента пишется через e: `1e9`, `2.5e-3`.

### Целочисленное деление: почему 7 / 2 — это 3

Самая частая ловушка новичка в Go — деление целых чисел. Оператор / для двух целых типов выполняет целочисленное деление: дробная часть отбрасывается без округления. 7 / 2 — это 3, 1 / 2 — это 0, -7 / 2 — это -3 (усечение к нулю, а не в меньшую сторону).

Хотите честное деление? Хотя бы один операнд должен быть float: `7.0 / 2` даст 3.5. Обычно это делают явным преобразованием: `float64(x) / 2`.

Рядом с / живёт оператор остатка %: `7 % 2` — это 1. Он незаменим для проверки чётности (`n % 2 == 0`), циклических индексов (`i % len(list)`) и разбиения на страницы. Запомните связку: деление целых усекает, остаток возвращает то, что «не поделилось».

Коварный момент: ошибка проявляется не в месте деления, а далеко потом, когда результат неожиданно оказался целым. Если переменная должна быть дробной, проверяйте типы всех участников выражения.

### Песочница: деление и остаток

Запустите код и сверьте вывод с ожиданиями. Затем замените apple := 10 на apple := 10.0 — программа не скомпилируется, потому что % не работает с float. Верните 10 и поменяйте friends на 4: сколько достанется каждому?

```go
package main

import "fmt"

func main() {
	fmt.Println("7 / 2 =", 7/2)
	fmt.Println("7 % 2 =", 7%2)
	fmt.Println("7.0 / 2 =", 7.0/2)
	fmt.Println("-7 / 2 =", -7/2)

	apple := 10
	friends := 3
	fmt.Println("Каждому по", apple/friends, "яблока, осталось", apple%friends)
}
```

### Проверьте себя: целочисленное деление

**Вопрос:** Что напечатает `fmt.Println(9 / 2)`?

- 4.5
- 5
- ✅ 4
- ошибка компиляции

Оба операнда целые, поэтому / выполняет целочисленное деление: 4.5 усекается до 4. Округления нет — дробная часть просто отбрасывается. Чтобы получить 4.5, нужен хотя бы один float-операнд: 9.0 / 2.

### Преобразование типов: только руками

Go не выполняет неявных преобразований между числовыми типами. Сложить int и float64 напрямую нельзя — программа не скомпилируется с ошибкой «mismatched types int and float64». Преобразование пишется явно, как вызов функции: `float64(x)`, `int(pi)`, `byte(n)`.

Это может раздражать после JavaScript, где всё складывается со всем. Но у строгого подхода есть цена и выгода: цена — чуть больше печатания; выгода — в коде никогда не происходит «магических» потерь данных. Посмотрев на строку `total := float64(count) * price`, вы точно знаете, где случилось преобразование.

При преобразовании вниз данные теряются по правилам усечения. `int(99.99)` — это 99: дробная часть отбрасывается, никакого округления. Для честного округления используется math.Round из одноимённого пакета. А `byte(300)` даст 44: 300 не помещается в диапазон 0-255, и лишние старшие биты отсекаются (300 - 256 = 44).

### Явные преобразования в действии

```go
package main

import "fmt"

func main() {
	price := 99.99
	whole := int(price) // усечение, не округление
	fmt.Println("Целая часть:", whole)

	count := 3
	total := float64(count) * price
	fmt.Println("Сумма:", total)

	fmt.Println("byte(300):", byte(300))
}
```

int(price) отбрасывает 0.99, не округляя. float64(count) превращает 3 в 3.0, после чего умножение проходит без ошибок типов. byte(300) демонстрирует отсечение битов: 300 выходит за диапазон byte, остаётся 300 - 256 = 44.

### Что выведет код?

```go
package main

import "fmt"

func main() {
	x := 7
	y := 2
	fmt.Println(x/y, float64(x)/y)
}
```

**Что выведет программа?**

- 3.5 3.5
- ✅ 3 3.5
- 3 3
- ошибка компиляции

x/y — деление двух int, результат 3. float64(x)/y — x преобразован во float64, поэтому деление вещественное: 3.5. Обратите внимание: сам x при этом не меняется, преобразование создаёт новое значение.

### Переполнение: что происходит на границе

Каждый целочисленный тип ограничен. У int8 диапазон от -128 до 127 — и добавление единицы к 127 в настоящем Go не вызывает ни ошибки, ни исключения: значение «заворачивается» и становится -128. Такой инцидент называется переполнением, и компилятор его не ловит — переменная тихо содержит бессмысленное число.

Переполнение бьёт по конкретным местам: вычитание в счётчиках обратного отсчёта, умножение больших чисел, суммы по длинным массивам. Классика — неаккуратный uint: он не может быть отрицательным, поэтому `u - 1` при u = 0 даёт максимальное значение типа, а не -1. История программирования полна уязвимостей, построенных на этом эффекте.

Как защищаться? Первое: работайте с int — у него диапазон настолько велик, что переполнение в учебных задачах недостижимо. Второе: если данные приходят извне и теоретически велики, проверяйте границы перед арифметикой. Третье: для по-настоящему больших чисел в стандартной библиотеке есть math/big — произвольная точность ценой скорости.

> **Переполнение не паникует.** В Go переполнение целых — это тихое заворачивание значения, а не ошибка времени выполнения. Программа продолжит работать с неверным числом. Именно поэтому места с потенциально большими вычислениями стоит проверять на границы вручную — или использовать типы большего размера.

### byte и rune: числа в маске

Два типа из этого урока заслуживают отдельного знакомства, потому что они притворяются не числами. byte — это псевдоним uint8, то есть число от 0 до 255. rune — псевдоним int32, число-код символа в таблице Unicode. Технически это целые числа; семантически они описывают байт и символ.

Псевдоним здесь означает дословно: byte и uint8 — один и тот же тип, можно даже присваивать друг другу без преобразований. То же верно для rune и int32.

Зачем знать это уже сейчас? Во-первых, чтобы не удивляться, когда строковый индекс возвращает число: s[0] у строки — это byte, то есть 65 для «A». Во-вторых, чтобы понимать сообщения об ошибках вроде «cannot use rune (variable of type rune) as int32». А подробный разговор о строках, байтах и рунах — тема следующего урока, где мы будем резать строки и считать кириллические символы.

### Проверьте себя: результат int()

**Вопрос:** Что напечатает `fmt.Println(int(2.7), int(-2.7))`?

- 3 -3
- ✅ 2 -2
- 2 -3
- ошибка: int не принимает отрицательные дроби

int() усекает дробную часть к нулю: 2.7 становится 2, -2.7 становится -2. Это не округление до ближайшего и не floor — просто отбрасывание хвоста. Для округления есть math.Round, для floor — math.Floor.

### Соберите код: преобразование типов

Впишите типы преобразований так, чтобы программа считала средний балл и напечатала его без дробной части.

```go
package main

import "fmt"

func main() {
	sum := 21
	n := 4
	avg := ___(sum) / ___(n)
	rounded := int(avg)
	fmt.Println(avg, rounded)
}
```

Подсказка: Целочисленное деление даст 5, а не 5.25. Чтобы деление стало вещественным, оба операнда нужно привести к float64.

Правильные ответы в пропусках: `float64`, `float64`

### Карточки: числовые типы

- **Какой тип получит x в `x := 42`?** — int — целые литералы без явного типа становятся int.
- **Результат 7 / 2 и 7 % 2** — 3 и 1. Деление целых усекает дробную часть, % возвращает остаток.
- **float64 vs float32** — float64 — около 15-16 значащих цифр, выбор по умолчанию. float32 — около 7 цифр, экономит память.
- **int(99.99)** — 99 — дробная часть отбрасывается (усечение), округления нет.
- **byte и rune — это что?** — Псевдонимы числовых типов: byte = uint8 (0-255), rune = int32 (код символа Unicode).
- **Можно ли сложить int и float64?** — Нет — только через явное преобразование: float64(i) + f. Неявных преобразований в Go нет.

## Коротко: что запомнить

- По умолчанию целые — это int, дробные — float64; явные типы нужны для форматов данных.
- Деление двух целых усекает дробную часть: 7/2 = 3; остаток берётся через %.
- Хотя бы один float-операнд — и деление станет вещественным: 7.0/2 = 3.5.
- Преобразования типов только явные: int(99.99) = 99, float64(3) = 3.0.
- byte = uint8, rune = int32 — числовые типы с символьной семантикой.
- Переполнение заворачивает значение молча: 127 + 1 для int8 даёт -128.
- 0.1 + 0.2 не равно 0.3 — это свойство двоичных дробей, а не баг Go.

## Домашнее задание

Напишите программу с двумя константами: totalSeconds = 3661 и price = 79.5. Вычислите и выведите: полные часы (целочисленное деление), остаток секунд (остаток), а также стоимость трёх с половиной единиц товара, приведя типы корректно (подсказка: 3.5 умножить на float64 от price не сработает — price уже float64). Проверьте вывод на глазах: часы = 1, остаток = 61, стоимость = 278.25.

## Вопросы и ответы по уроку

### Какой тип выбрать: int или int64?

По умолчанию int — на современных 64-битных платформах он совпадает с int64. Явный int64 нужен там, где размер зафиксирован контрактом: сериализация, база данных, сетевой протокол. Для счётчиков, длин и индексов всегда хватает int.

### Почему 0.1 + 0.2 != 0.3?

Дробные числа хранятся в двоичном виде по стандарту IEEE 754, а 0.1 в двоичной системе — бесконечная дробь. Небольшая погрешность накапливается, и сумма получается 0.30000000000000004. Для денег используйте целые копейки или пакеты вроде shopspring/decimal.

### Как округлить float до целого?

int(x) не округляет, а усекает. Для округления используйте math.Round(x) — он вернёт float64, который можно привести к int: int(math.Round(2.7)) даст 3. Есть также math.Floor и math.Ceil.
