На этом шаге рассмотрим определение пользователльских типов в Go.
Пользовательские типы определяются с помощью ключевого слова type:
type имяТипа определениеТипа
Имя типа может быть любым допустимым идентификатором, уникальным в пределах пакета или функции. В качестве определения типа могут использоваться имя любого встроенного типа (например, string, int, срез, отображение или канал), интерфейса, определение структуры или сигнатура функции.
В некоторых ситуациях бывает достаточно просто определить пользовательский тип, в других бывает необходимо добавить методы, чтобы сделать его по-настоящему полезным. Приведем примеры пользовательских типов без методов.
type Count int type StringMap map[string]string type FloatChan chan float64
Ни один из этих типов не выглядит особенно полезным, хотя их использование может улучшить удобочитаемость программы и в будущем изменить тип, лежащий в его основе. То есть они играют роль простейшего механизма абстракции.
var i Count = 7 i++ fmt.Println(i) sm := make(StringMap) sm["key1"] = "Значение1" sm["key2"] = "Значение2" fmt.Println(sm) fc := make(FloatChan, 1) fc <- 2.29558714939 fmt.Println(<-fc)
Типы, подобные типам Count, StringMap и FloatChan, основанные непосредственно на встроенных типах, можно использовать точно так же, как сами встроенные типы. Например, к значению пользовательского типа StringSlice []string можно применить встроенную функцию append(), но его необходимо будет преобразовать в значение встроенного типа, прежде чем передать функции, ожидающей получить значение этого встроенного типа. А иногда бывает необходимо выполнить обратное действие и преобразовать значение встроенного типа в значение пользовательского типа, чтобы получить возможность использовать дополнительные методы пользовательского типа.
При работе с функциями высшего порядка часто бывает удобно объявить тип, определяющий сигнатуру передаваемой функции.
type RuneForRuneFunc func(rune) rune
Здесь определяется сигнатура функции, принимающей и возвращающей единственное значение типа rune.
var removePunctuation RuneForRuneFunc
Переменная removePunctuation предназначена для хранения ссылки на функцию типа RuneForRuneFunc (то есть с сигнатурой func(rune) rune). Подобно всем переменным в языке Go, она автоматически инициализируется нулевым значением , то есть в данном случае значением nil.
phrases := []string{"Казнить, нельзя, помиловать.", "Быть или не быть."} removePunctuation = func(char rune) rune { if unicode.Is(unicode.Terminal_Punctuation, char) { return -1 } return char } processPhrases(phrases, removePunctuation)
Здесь создается анонимная функция с сигнатурой, соответствующей RuneForRuneFunc, и передается пользовательской функции processPhrases().
func processPhrases(phrases []string, function RuneForRuneFunc) { for _, phrase := range phrases { fmt.Println(strings.Map(function, phrase)) } }
Архив с примерами можно взять здесь.
На следующем шаге рассмотрим добавление дополнительных методов в Go.