Константы в golang

Константы

В языке Go, термин константа используется для представления постоянных, неизменяемых значений, таких как 4, 1.23, true, "Привет" и так далее.

Литералы являются константами

Литерал — лексема, которая непосредственно представляет некоторое значение [ГОСТ 28397-89]

Все литералы в Go, будь то целочисленный литерал, например 2 или 2000, литерал с плавающей точкой, например 2.34, 1.78, логический литерал, например true и false или строковые литералы, например "Привет" и "Golang", являются константами.

Тип Описание Пример
integer Целочисленный 5000, 123456
floating-point Число с плавающей точкой 7.89, 456.987
boolean Логический true, false
rune 4-байтовое unicode представление
символов UTF-8
'A', 'ä'
complex Комплексное число 2.7i, 1 + 3i
string Строка "Привет", "Hello"

Объявление констант

Литералы, по сути, являются константами без имени. Для объявления константы с определенным именем, можно использовать ключевое слово const. Пример:

Или же, можно объявить переменную с явным указанием типа:

Так же, возможно множественное определение констант в одном выражении:

Как можно догадаться, константы не могут быть переопределены. Это означает. что нельзя присвоить константе другое значение после её объявления.

Типизированные и нетипизированные константы

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

Go  является статически-типизированным языком программирования. Это означает, что тип каждой переменной определяется компилятором во время компиляции.

Если смотреть глубже, система типов не позволяет выполнять операции, в которых используются разные типы данных. Например, запрещено складывать значения типа float64  и int , или даже in64 и int .

В таких случаях необходимо использовать явное приведение типов

Такое поведение Go отличает его от других языков со статической типизацией, как C, C++ или Java, которые позволяют автоматически конвертировать меньшие типы в большие при совместном использовании их в одном выражении. Например int может быть автоматически сконвертирован в long, float или double.

Причина отсутствия неявного приведения типов в Go объясняется его разработчиками следующим образом:

Удобство автоматической конвертации между типами в C перечеркивается путанницей, которую она вносит. Когда выражение является беззнаковым? На сколько значение является большим? Было ли переполнение? Является ли результат платформонезависимым? Так же, это усложняет компилятор: «обычные арифметические преобразования» не так просты в реализации и реализации могут различаться в зависимости от архитектуры. В угоду переносимости, мы решили сделать эти вещи прозрачными и простыми, что привело к необходимости использования явных преобразований типов в коде.

Итак, Go не поддерживает неявное приведение типов и требует от разработчика явно приводить типы при использовании разных типов в одном выражении.

Но как система типов Go работает с константами? Рассмотрим следующие выражения, которые являются валидными в Go.

Какой тип имеет константа со значением 10 в приведенных выражениях? Более того, если в Go нет неявного приведения типов, почему нет необходимости использовать выражения такого вида?

Ответы на эти вопросы кроются в том, каким образом Go обрабатывает константы.

Нетипизированные константы

Все константы в Go, именованные или неименованные, являются нетипизированными до тех пор, пока тип не будет задан явно. Например, все эти константы являются нетипизированными:

Они остаются нетипизированными даже после того, как им назначены имена:

Несмотря на использование терминов целочисленная, логическая и других, константы остаются нетипизированными. Дело в том, что значение 1 является целым числом, 4.5 — числом с плавающей точкой, "Привет" — строкой, но это, всего лишь, значения. Они еще не имеют определенного типа, например int32, float64 или string, что заставило бы их подчинятся строгим правилам типизации Go.

По факту, значение 1 является нетипизированным и может быть присвоено любой переменной, тип которой совместим с целыми числами.

Не смотря на то, что значение 1 является не типизированным, оно является нетипизированным целочисленным. Поэтому оно может быть использовано только там, где допустимо использование целых чисел. Нельзя присвоить строковое значение переменной с логическим типом.

Аналогично, нетипизированная переменная с плавающей точкой 4.5 может быть использована в любых выражениях, где разрешено использование чисел с плавающей точкой.

Рассмотрим пример использования нетипизированных строковых констант.

В языке Go возможно создание псевдонимов типов при помощи ключевого слова type.

Следуя строгой типизации Go, невозможно присвоить переменной типа RichString значение переменной типа string.

Однако, переменной типа RichString возможно присвоить значение строковой нетипизированной константы. Это обусловлено тем, что тип RichString является совместимым со строковым.

Константы и вывод типов: тип по умолчанию

Язык Go поддерживает вывод типов.  Это означает, что тип переменной может быть выведен из типа значения, которое используется для инициализации этой переменной. Так что, возможно объявление переменной с указанием её начального значения и без указания типа, в таком случае, Go автоматически определит тип.

Как это работает? Если учесть, что константы в Go являются нетипизированными, какой тип будет присвоит переменной a? Вариантов не мало: int8, int16, int32, int64 и int.

Каждая нетипизированная константа в Go имеет свой тип по умолчанию. Типы по умолчанию используются когда значение константы присваивается переменной без явного указания типа.

В языке Go используются следующие типы констант по умолчанию:

Константа Тип по умолчанию
Целое число (12, 89) int
Число с плавающей точкой (2.71, 9.87) float64
Комплексное число (2+4i) complex128
Символ (‘а’, ‘®’) rune
Логические значение (true, false) bool
Строка («Привет») string

Итак, в примере выше,  var a = 5, в виду отсутствия явного указания типа, для переменной a будет использован тип по умолчанию int.

Типизированные константы

Язык Go позволяет определять типизированные константы.

Аналогично переменным, правила строгой типизации Go действуют и на типизированные константы.

Использование типизированных констант лишает гибкости в их использовании. Значение типизированных констант нельзя присваивать переменным с совместимым типом или использовать в математических выражениях совместно с константами других типов без явного приведения типов. Типизированные константы нужно использовать разумно. В большинстве случаев, достаточно нетипизированных констант.

Числовые выражения, включающие константы

Нетипизированные константы могут совместно использоваться в любых числовых выражениях. Это работает без каких-либо подводных камней.

В примере выше, 7.5 является нетипизированной константой с плавающей точной, а 5 нетипизированной целочисленной константой. Результат вычисления 1.5 является нетипизированной константой с плавающей точкой, типом по умолчанию для которой является float64. Соответственно, переменной result был присвоен тип float64.

Другой пример

Каким будет результат выполнения программы?

Если взять обычный калькулятор и вычислить значение выражения по математическим правилам, получим 12.5.

Но в результате выполнения программы мы получим 12.

Так, как оба операнда 25 и 2 являются нетипизированными целочисленными константами, то и значение выражения было приведено к целому числу.

Корректного результата вычисления можно добиться одним из следующих способов.

Еще один пример

Каким будет результат в этот раз?

Ожидаемым результатом для большинства других языков и калькулятора будет 17. В случае с Go, результатом будет 16.5.

Для того, чтобы понять, как получился такой результат, рассмотрим этапы вычисления значения выражения.

Для получения корректного результата, можно использовать уже знакомые приёмы.

Заключение

Нетипизированные константы являются интересным архитектурным решением, принятым авторами Go. Не смотря на то, что в Go существует строгая система типов, нетипизированные константы добавляют гибкости в совместном использовании разных типов в любых выражениях.

Оригинал: Working with Constants in Golang.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *