Значения, константы и числа
Целые типы и переполнение, знаковые и беззнаковые, строки, руны и байты, константы iota и управление потоком.
7 вопросов
JuniorТеорияЧастоКакие размеры целых предоставляет Go и что определяет ширину int?
Какие размеры целых предоставляет Go и что определяет ширину int?
В Go есть целые фиксированной ширины 8, 16, 32 и 64 бита, знаковые (int8…int64) и беззнаковые (uint8…uint64). Обычные int и uint платформозависимы — 64 бита почти на всех современных целях, 32 бита на 32-битных сборках GOARCH — ширина задана реализацией.
Типичные ошибки
- ✗Считать, что
intвсегда 32 бита или всегда 64 бита, независимо от целевой платформы - ✗Полагать, что ширина
intвыбирается динамически по значению, а не фиксируется на этапе компиляции - ✗Путать
intсint32и полагаться на гарантированную 32-битную ширину в сериализованных данных
Уточняющие вопросы
- →Что такое
uintptrи как его ширина связана сint? - →Почему сериализуемые форматы должны использовать
int64, а неint?
JuniorТеорияЧастоКакие области видимости есть в Go и как решается межпакетная видимость?
Какие области видимости есть в Go и как решается межпакетная видимость?
Go разрешает идентификаторы через вложенные области видимости: блочная (внутренние {}, допускающая shadowing), функциональная, файловая (импорты), пакетная (top-level объявления, видимые каждому файлу пакета) и universe (builtins). Межпакетная видимость отдельна и решается регистром: идентификатор с Заглавной буквы экспортируемый, с маленькой — неэкспортируемый.
Типичные ошибки
- ✗Искать ключевые слова
public/private— Go решает экспорт по регистру буквы - ✗Забывать, что блочная область есть и внутренние блоки могут затенять внешние имена
- ✗Думать, что объявления уровня пакета видны только в собственном файле
Уточняющие вопросы
- →Как shadowing во внутреннем блоке влияет на внешнюю переменную?
- →Доступно ли неэкспортируемое поле через экспортируемую встроенную struct?
JuniorТеорияЧастоВ чём разница между знаковыми и беззнаковыми целыми типами в Go?
В чём разница между знаковыми и беззнаковыми целыми типами в Go?
Знаковые типы (int8…int64, int) используют дополнительный код и хранят отрицательные и положительные значения. Беззнаковые (uint8…uint64, uint, uintptr) хранят только неотрицательные значения; при переполнении они оборачиваются по модулю 2^n, а не вызывают ошибку.
Типичные ошибки
- ✗Думать, что беззнаковая арифметика прерывается или насыщается при переполнении — Go оборачивает по модулю 2^n без ошибки
- ✗Полагать, что знаковый тип отводит целый бит величины под флаг знака вместо дополнительного кода
- ✗Считать, что
uintможет кратко удержать отрицательное промежуточное значение перед ограничением
Уточняющие вопросы
- →Что происходит при вычитании большего
uintиз меньшего? - →Почему Go запрещает неявное преобразование между
intиuint?
JuniorТеорияЧастоКак работает switch-case в Go и что делает break?
Как работает switch-case в Go и что делает break?
switch в Go выполняет только первый совпавший case и затем останавливается: неявного проваливания нет, поэтому явный break нужен редко. Внутри switch, вложенного в цикл, break выходит только из switch (для цикла используйте метку). fallthrough заставляет выполнить следующий case, case может перечислять значения через запятую, а switch без выражения ведёт себя как цепочка if/else.
Типичные ошибки
- ✗Ожидать проваливания как в C и ставить
breakпосле каждого case - ✗Думать, что
breakв switch внутри цикла выходит из цикла, а не из switch - ✗Забывать, что
fallthroughсуществует, чтобы намеренно выполнить следующий case
Уточняющие вопросы
- →Как выйти из цикла изнутри switch, находящегося в его теле?
- →В чём разница между type switch и обычным switch по значению?
JuniorТеорияИногдаКак вычислить диапазон int64 для положительных чисел в Go?
Как вычислить диапазон int64 для положительных чисел в Go?
int64 — знаковый тип в дополнительном коде, поэтому его 64 бита делятся между отрицательными и неотрицательными значениями: он охватывает −2^63 … 2^63−1. Положительный диапазон, следовательно, равен 0 … 2^63−1, то есть 9223372036854775807 — значение math.MaxInt64.
Типичные ошибки
- ✗Вычислять положительный потолок как 2^64−1 — это максимум беззнакового
uint64, а неint64 - ✗Включать сам 2^63 как максимум вместо 2^63−1 (ошибка на единицу из-за забытого нуля)
- ✗Думать, что бит знака хранится отдельно от значения, а не является частью дополнительного кода
Уточняющие вопросы
- →Каково самое отрицательное значение
int64и почему оно не зеркально максимуму? - →Чему равно отрицание
math.MinInt64и почему оно переполняется?
JuniorДебаггингИногдаПочему этот average возвращает 1.0 для []int{1, 2} вместо 1.5?
Почему этот average возвращает 1.0 для []int{1, 2} вместо 1.5?
sum / len(nums) — это целочисленное деление, которое усекает к нулю до приведения float64(...) — 3 / 2 даёт 1, затем приводится к 1.0. Пустой срез к тому же паникует делением на ноль. Исправление — сперва привести: float64(sum) / float64(len(nums)) и проверять len(nums) == 0.
Типичные ошибки
- ✗Приводить к
float64после деления, а не до него - ✗Забывать, что целочисленное деление усекает к нулю, а не округляет
- ✗Не проверять
len(nums) == 0, что паникует делением на ноль
Уточняющие вопросы
- →Почему
float64(sum / len(nums))всё равно усекает, хотя результат — float? - →Какое значение даёт
5 / 2в Go и чем оно отличается от5.0 / 2?
JuniorКодИногдаЧто выведут len(s) и utf8.RuneCountInString(s) для s := "héllo"?
Что выведут len(s) и utf8.RuneCountInString(s) для s := "héllo"?
Выведет 6 5. len(s) считает байты, а é занимает два байта в UTF-8, поэтому длина в байтах равна 6, а число рун (символов) — 5. Проход for i, r := range s итерирует руны, тогда как индексация s[i] возвращает один байт, а не символ.
Типичные ошибки
- ✗Считать, что
len(s)возвращает число символов — он возвращает число байтов - ✗Думать, что
s[i]индексирует руны; он индексирует байты - ✗Забывать, что многобайтовые символы UTF-8, как
é, занимают больше одного байта
Уточняющие вопросы
- →Сколько итераций делает
for i, r := range sи каким будетiпослеé? - →Почему
[]rune(s)выделяет память, аrangeпо строке — нет?