Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 5 из 25 ~20 мин +50 XP

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

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

Содержание урока · 10 разделов

Целые числа: 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 квинтиллионапо умолчанию для всех целых
int88 бит-128 до 127компактные знаковые значения
int3232 битаоколо -2,1 млрд до 2,1 млрдпротоколы, руны (rune = int32)
int6464 битаоколо ±9,2 квинтиллионаметки времени, большие счётчики
uint8 (byte)8 бит0 до 255байты, байтовые срезы
uint6464 бита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: сколько достанется каждому?

Вывод

Запустите код, чтобы увидеть вывод.

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

Что напечатает `fmt.Println(9 / 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.

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

Прочитайте код и выберите, что он выведет:

package main

import "fmt"

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

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

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

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

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

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))`?

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

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

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

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

Термин

Какой тип получит x в `x := 42`?

нажмите, чтобы перевернуть
Определение

int — целые литералы без явного типа становятся int.

1 / 6

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

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

  • По умолчанию целые — это 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.

Личные заметкиПусто
Хранятся только в вашем браузере (Go Base · Типы данных: числа)

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

Какой тип выбрать: 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.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Следующая ступень учебного пути

Go Pro25 уроков~14 чпрактика25 уроков уже доступны

Продвинутые возможности Go: от замыканий до рефлексии

Продвинутый курс Go: замыкания, defer, горутины, каналы, контекст, интерфейсы, дженерики, рефлексия, тесты и JSON. 25 уроков с практикой в браузере.

  • Писать и читать конкурентный код: go-функции, каналы, select
  • Управлять жизненным циклом операций через context
  • Проектировать API на интерфейсах
  • Использовать дженерики без злоупотребления