Skip to content

Константы в Go

Значение константы не может быть изменено во время выполнения. После присваивания оно не может быть изменено. Значение может происходить только из:

  • Литералов
  • Других идентификаторов констант
  • Константных выражений
  • Преобразований типов, результатом которых являются константы
  • iota

Константы могут быть только основных типов данных, не могут быть:

  • Другими типами, кроме основных, такими как структуры, интерфейсы, срезы, массивы и т.д.
  • Возвращаемыми значениями функций

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

Инициализация

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

go
const name string = "Jack" // литерал

const msg = "hello world" // литерал

const num = 1 // литерал

const numExpression = (1+2+3) / 2 % 100 + num // константное выражение

Если просто объявить без указания значения, код не скомпилируется:

go
const name string

Компилятор выдаст ошибку:

missing init expr for name

Для объявления нескольких констант можно использовать () для повышения читаемости. Можно использовать несколько () для группировки:

go
const (
   Count = 1
   Name  = "Jack"
)

const (
   Size = 16
   Len  = 25
)

В одной группе констант константы после уже присвоенной константы могут не получать значение — их значение по умолчанию равно значению предыдущей константы:

go
const (
  A = 1
  B // 1
  C // 1
  D // 1
  E // 1
)

iota

iota — встроенный идентификатор константы, обычно используется для представления безтипового целочисленного порядкового номера в объявлении константы, обычно используется в скобках.

go
const iota = 0

Несколько примеров использования:

go
const (
   Num = iota // 0
   Num1 // 1
   Num2 // 2
   Num3 // 3
   Num4 // 4
)

Также можно написать так:

go
const (
   Num = iota*2 // 0
   Num1 // 2
   Num2 // 4
   Num3 // 6
   Num4 // 8
)

И ещё так:

go
const (
   Num = iota << 2*3 + 1 // 1
   Num1 // 13
   Num2 // 25
   Num3 = iota // 3
   Num4 // 4
)

Из приведённых примеров видно, что iota инкрементируется. Первое константное выражение с iota определяет шаблон, и последующие константы автоматически получают значения согласно изменению порядкового номера, пока не будет сброшено новым const. Этот порядковый номер — фактически относительный номер строки кода относительно начальной строки текущей группы. Пример:

go
const (
  Num  = iota<<2*3 + 1 // 1 первая строка
  Num2 = iota<<2*3 + 1 // 13 вторая строка
  _ // 25 третья строка
  Num3 //37 четвёртая строка
  Num4 = iota // 4 пятая строка
  _ // 5 шестая строка
  Num5 // 6 седьмая строка
)

В примере используется анонимный идентификатор _ для занятия строки. Значение iota по сути — разница между строкой, где находится iota, и первой строкой текущей группы const. Разные группы const не влияют друг на друга.

Перечисления

В Go нет отдельного типа данных для перечислений, в отличие от других языков, где обычно есть enum. В Go перечисления реализуются через пользовательский тип + const + iota. Простой пример:

go
type Season uint8

const (
  Spring Season = iota
  Summer
  Autumn
  Winter
)

Эти перечисления фактически являются числами. Go не поддерживает прямое преобразование в строки, но мы можем добавить метод к пользовательскому типу для возврата строкового представления, реализовав интерфейс Stringer:

go
func (s Season) String() string {
  switch s {
  case Spring:
    return "spring"
  case Summer:
    return "summer"
  case Autumn:
    return "autumn"
  case Winter:
    return "winter"
  }
  return ""
}

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

Однако у этого подхода есть недостатки:

  • Небезопасность типов: поскольку Season — пользовательский тип, можно выполнить принудительное преобразование других чисел в этот тип:

    go
    Season(6)
  • Громоздкость: строковое представление нужно реализовывать вручную

  • Слабая выразительность: поскольку const поддерживает только основные типы данных, значения перечислений могут быть представлены только строками и числами

Автору непонятно, почему перечисления не поддерживаются на уровне языка — это определённо было бы преимуществом.

Golang by www.golangdev.cn edit