Как Go обрабатывает арифметику нетипизированных констант, если промежуточный результат выходит за диапазон машинных типов?
Нетипизированные константы вычисляются во время компиляции с точностью, достаточной для представления их значения, поэтому промежуточный результат не обязан помещаться в int или другой машинный тип. Ошибка возникает тогда, когда результат требуется представить в конкретном типе, но он в него не помещается.
Разделение констант и обычных значений позволяет безопасно вычислять размеры, маски, временные интервалы и другие известные при компиляции величины без преждевременного ограничения диапазоном конкретного типа. Подход также делает числовые литералы удобными: их тип часто определяется только в месте использования.
Если считать каждое выражение сразу имеющим тип int, большие промежуточные значения могли бы переполниться или потребовали бы ранних явных преобразований. В Go это не происходит для нетипизированных констант: компилятор сохраняет точное значение, но затем проверяет его представимость в контексте назначения.
Важно отличать переполнение константы от переполнения переменной. Первое обычно приводит к ошибке компиляции, второе возможно во время выполнения и зависит от типа переменной.
Нетипизированная числовая константа не привязана к int, int64 или другому конкретному типу до тех пор, пока этого не потребует контекст. Арифметика над такими константами выполняется на этапе компиляции; дробные значения и целые значения сохраняют семантику констант, а не поведение машинной арифметики с фиксированной шириной.
В примере n корректен: сам по себе он остаётся нетипизированной константой. m также вычисляется во время компиляции и получает значение, которое можно представить в подходящем типе. Присваивание n переменной uint8 завершилось бы ошибкой, поскольку значение не помещается в диапазон uint8.
Контекст может не только ограничить диапазон, но и определить тип. Например, присваивание нетипизированной константы переменной делает её значением типа переменной, если значение представимо. Явное преобразование не отменяет проверку: преобразуемое константное значение тоже должно быть допустимо для целевого типа.
Это правило относится именно к константам. Если сначала получить обычное значение фиксированного типа, дальнейшие операции выполняются по правилам этого типа, включая возможное переполнение целых типов во время выполнения.
Разработчик рассчитывал битовую маску как константное выражение и затем присваивал её полю типа uint32. На этапе вычисления маска была корректна, но после добавления нового флага перестала помещаться в uint32.
Вариант с хранением промежуточного результата в int плох: он раньше связывает выражение с размером int и может сделать код зависимым от архитектуры. Вариант с немедленным приведением к uint32 скрывает проблему до места приведения и может привести к ошибке компиляции там, где её сложнее понять.
Выбранное решение — оставить расчёт константным и явно проверить, что итоговый набор флагов соответствует контракту uint32. В результате переполнение обнаруживается компилятором при изменении набора флагов, а не проявляется как неверная маска в работающем сервисе.
Нет. Практическая реализация и спецификация ограничивают множество представимых констант; это не означает произвольную бесконечную точность без предела. Но кандидатский вывод остаётся таким: константа не ограничивается диапазоном int только потому, что в выражении присутствует целочисленный литерал.
int64?Если значение не представимо в int64, программа не скомпилируется. Компилятор не выполняет молчаливое усечение, как это могло бы произойти при некоторых операциях над обычными значениями фиксированного типа.
Константное выражение проверяется компилятором, поэтому непредставимое значение вызывает ошибку компиляции. Операция над переменной выполняется в её конкретном типе; для беззнаковых целых результат определяется арифметикой по модулю, а для знаковых целых результат должен рассматриваться с учётом правил Go и конкретного типа, а не как произвольная точная константная арифметика.