Перечисления и йота - множество советов и приемов с примерами работающего кода.

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

Что такое Enum? ★

Перечисление объединяет связанные константы в один тип.

Примеры перечислений:

  • Часовые пояса: EST, CST…
  • Размеры футболки: маленький, средний, большой
  • Статусы сервера: "Неизвестно", "Работает", "Остановлен", "Возобновлен"

Зачем нужны перечисления?

  • Группировка и ожидание только некоторых связанных значений
  • Поделиться общим поведением
  • Избегает использования недопустимых значений
  • Для повышения читабельности кода и удобства сопровождения

Как можно имитировать перечисление в Go?

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

★ Во-первых: объявите новый пользовательский тип: будний день.

Weekday объединит константы перечисления под общий тип.

type Weekday int

★ Второе: объявить связанные константы для буднего дня

Присвойте им разные числовые значения, чтобы они не конфликтовали.

const (
   Sunday    Weekday = 0
   Monday    Weekday = 1
   Tuesday   Weekday = 2
   Wednesday Weekday = 3
   Thursday  Weekday = 4
   Friday    Weekday = 5
   Saturday  Weekday = 6
)
fmt.Println(Sunday)    // prints 0
fmt.Println(Saturday)  // prints 6

Создание общего поведения для перечисления Weekday

Вы прикрепляете методы к типу, чтобы определить его поведение.

Прикрепленные методы будут неотъемлемыми частями Weekday и совместно используемыми константами Weekday.

Метод String ():

func (day Weekday) String() string {
    // declare an array of strings
    // ... operator counts how many
    // items in the array (7)
    names := [...]string{
        "Sunday", 
        "Monday", 
        "Tuesday", 
        "Wednesday",
        "Thursday", 
        "Friday", 
        "Saturday"}
    // → `day`: It's one of the
    // values of Weekday constants.    
    // If the constant is Sunday,
    // then day is 0.
    //
    // prevent panicking in case of
    // `day` is out of range of Weekday
    if day < Sunday || day > Saturday {
      return "Unknown"
    }
    // return the name of a Weekday
    // constant from the names array 
    // above.
    return names[day]
}

Попробуем:

fmt.Printf("Which day it is? %s\n", Sunday)
// Which day it is? Sunday

Метод выходных дней ():

func (day Weekday) Weekend() bool {
    switch day {
    case Sunday, Saturday:   // If day is a weekend day
        return true
    default:                 // If day is not a weekend day
        return false
    }
}

Соглашение: вместо IsWeekend мы просто используем Weekend.

Попробуем:

fmt.Printf("Is Saturday a weekend day? %t\n", Saturday.Weekend())
// Is Saturday a weekend day? true

Автоматическое создание имен

Вы можете использовать Stringer Роба Пайка для автоматического создания метода String.

# install the stringer tool
go get -u -a golang.org/x/tools/cmd/stringer
# grab the code from here 
# and save it in weekday.go
# inside your $GOPATH/src/enums
# then, run stringer to create 
# enum names automatically
stringer -type Weekday weekdays.go

Автоматизировать значения перечисления с помощью: iota

→ Числовой универсальный счетчик, начиная с 0

→ Used oтолько с constant объявлениями

→ Можно затенять. Пожалуйста, не делай этого.

Как пользоваться йотой?

Выражение йоты повторяется другими константами до тех пор, пока не появится другое присваивание или объявление типа.

Посмотрим, как йота тикает

йота увеличивается на 1 после каждой строки, кроме пустых строк и строк комментариев.

Когда не использовать йоту

const (
   RestartMarkerReply     = 110
   ServiceReadyInNMinutes = 120
   CommandOK              = 200
   CommandNotImplemented  = 202
   // ...
)

Не используйте йоту для списка предопределенных значений, таких как коды состояния FTP-сервера.

const (
    Fatal = iota
)

Просто присвойте 0 там. Это безвредно, но и в этом нет необходимости.

Этот раздел расширит ваше понимание йоты.

Базовое выражение

type Timezone int
const (
    // iota: 0, EST: -5    
    EST Timezone = -(5 + iota)
    
    // iota: 1, CST: -6
    CST
    
    // iota: 2, MST: -7
    MST
    
    // iota: 3, MST: -8
    PST
)

Сброс йоты

// iota reset: it will be 0.
const (
    Zero = iota  // Zero = 0
    One          // One = 1
)
// iota reset: will be 0 again
const (
    Two = iota   // Two = 0
)
// iota: reset
const Three = iota // Three = 0

Пропуск некоторых значений

type Timezone int
const (
    // iota: 0, EST: -5
    EST Timezone = -(5 + iota)
    // _ is the blank identifier
    // iota: 1
    _
    // iota: 2, MST: -7
    MST
    // iota: 3, MST: -8
    PST
)

О поведении йоты в комментариях и пустых строках

type Timezone int
const (
    // iota: 0, EST: -5
    EST Timezone = -(5 + iota)
    // On a comment or an empty
    // line, iota will not 
    // increase
    // iota: 1, CST: -6
    CST
    // iota: 2, MST: -7
    MST
    // iota: 3, MST: -8
    PST
)

Использование йоты посередине

const (
    One   = 1
    Two   = 2
    // Three = 2 + 1 => 3
    // iota in the middle
    Three = iota + 1
    // Four  = 3 + 1 => 4
    Four
)

Несколько йот в одной строке

const (
    // Active = 0, Moving = 0,
    // Running = 0
    Active, Moving, Running = iota, iota, iota
    // Passive = 1, Stopped = 1,
    // Stale = 1
    Passive, Stopped, Stale
)

В этой же строке все константы получат одинаковые значения йоты.

const (
    // Active = 0, Running = 100
    Active, Running = iota, iota + 100
    // Passive = 1, Stopped = 101
    Passive, Stopped
    // You can't declare like this.
    // The last expression will be
    // repeated
    CantDeclare
    // But, you can reset 
    // the last expression
    Reset = iota
    // You can use any other
    // expression even without iota
    AnyOther = 10
)

Повторение и удаление выражений

const (
    // iota: 0, One: 1 (type: int64)
    One  int64  = iota + 1
    // iota: 1, Two: 2 (type: int64)
    // Two will be declared as if:
    // Two int64 = iota + 1
    Two
    // iota: 2, Four: 4 (type: int32)
    Four int32  = iota + 2
    // iota: 3, Five: 5 (type: int32)
    // Five will be declared as if:
    // Five int32 = iota + 2
    Five
    // (type: int)
    Six = 6
    // (type: int)
    // Seven will be declared as if:
    // Seven = 6
    Seven
)

Будет повторено последнее использованное выражение и тип.

Эвены и форы

type Even bool
const (
    // 0 % 2 == 0 ==> Even(true)
    a = Even(iota % 2 == 0)
    // 1 % 2 == 0 ==> Even(false)
    b
    // 2 % 2 == 0 ==> Even(true)
    c
    // 3 % 2 == 0 ==> Even(false)
    d
)

Обратный отсчет

const (
    max = 10
)
const (
    a = (max - iota) // 10
    b                // 9
    c                // 8
)

Сканер текста Go stdlib также использует этот шаблон.

Производство алфавитов

const (
    // string will convert the
    // expression into string.
    //
    // or, it'll assign character
    // codes.
    a = string(iota + 'a') // a
    b                      // b
    c                      // c
    d                      // d
    e                      // e
)

Побитовые операции

type Month int
const (
    // 1 << 0 ==> 1
    January Month = 1 << iota
    February   // 1 << 1 ==> 2
    March      // 1 << 2 ==> 4
    April      // 1 << 3 ==> 8
    May        // 1 << 4 ==> 16
    June       // ...
    July
    August
    September
    October
    November
    December
    // Break the iota chain here.
    // AllMonths will have only
    // the assigned month values, 
    // not the iota's.
    AllMonths = January | February |
        March | April | May | June |
        July | August | September |
        October | November |
        December
)

При степени двойки этот код создает всеобъемлющую константу из предыдущих констант.

Остерегайтесь нулевого значения

type Activity int
const (
    Sleeping = iota
    Walking
    Running
)
func main() {
    var activity Activity
    // activity initialized to 
    // its zero-value of int
    // which is Sleeping
}

0 - это нулевое значение для целых чисел. Таким образом, вы не можете знать, инициализировано действие или нет; Он действительно в спящем состоянии?

йота + 1 трюк

const (
    Sleeping = iota + 1
    Walking
    Running
)
func main() {
    var activity Activity
    // activity will be zero, 
    // so it's not initialized
    activity = Sleeping
    // now you know that it's been
    // initialized
}

Используйте «iota + 1», чтобы убедиться, что тип перечисления инициализирован.

Неизвестный шаблон состояния

const (
    Unknown = iota
    Sleeping
    Walking
    Running
)

Начните с «Неизвестно», чтобы быть уверенным в инициализации перечисления.

▶ ︎ В греческом алфавите йота - девятая и самая маленькая буква (с точки зрения ее визуального представления). Произносится как это. Он представляет собой очень небольшое количество чего-то.

В векторной математике и в некоторых языках программирования он использовался для создания массива последовательных целых чисел, например 1, 2, 3, 4…⟧

Если вам, как и мне, интересно, вы можете прочитать реализацию констант и йоту в исходном коде Go. Йота объявлена ​​здесь как const iota = 0. И постоянная реализация находится здесь, а поведение увеличения йоты - здесь.

Йота фигурирует в книге Айверсона: Язык программирования (APL) 1962 года.

Йота позаимствована у APL одним из создателей Go, Кеном Томпсоном.

Обсуждение того, как заставить iota работать с переменными в Go 2.

Хорошо, на этом пока все. Спасибо, что дочитали до сих пор.

Давайте оставаться на связи: