Именованные типы и структуры
Скоро сказка сказывается, да не скоро дело делается. Двигаемся вперёд - медленно, но уверенно. Похоже, в этой главке мне нечем вас будет удивить. Как именованные типы, так и структуры весьма и весьма напоминают таковые в С/С++.
Именованные типы
Именованные типы являются по сути псевдонимами тех или иных существующих примитивов, и используются в основном либо для улучшения семантичности кода, либо с целью дальнейшего применения методов. О методах речь пойдёт в соответствующей главе, а сейчас просто объявим именованный тип.
Как видите, всё достаточно предсказуемо. Вы вероятно, могли отметить, что использование цикла for по диапазону week выглядело бы синтаксически несколько проще. Это верно. В таком случае мы бы избежали объявления переменной-счётчика итераций и приведения типов. Однако вспомните тот факт, что особенность отображений - недетерминированность порядка следования элементов. Таким образом, использованный нами способ перебора элементов является небольшой хитростью, использованной с целью сортировки элементов в выдаче. Пользуйтесь подобной техникой и вы, при необходимости.
Структуры
Как и в "голом" С, в языке Go нет классов. И, точно так же, структура является единственным составным (агрегированным) типом данных. Синтаксис же таков:
Элементы структуры называются полями. Очевидно, непроинициализированная структура имеет для каждого своего поля значение по умолчанию, равное значению по умолчанию для соответствующего примитива.
Часто непроинициализированную структуру объявляют таким образом:
Доступ к полям структуры осуществляется через оператор "точка" - .
Возможна упрощённая инициализация полей (подобная конструкция именуется структурным литералом):
Можно ещё более кратко:
Именование как самой структуры, так и каждого её поля определяет экспортируемость всей структуры или отдельного поля. Как и везде, работает "правило заглавной буквы". Структура, именованная со строчной буквы экспортироваться не будет. В экспортируемой структуре, поля, не определённые с прописной буквы, также экспортироваться не будут. То есть часть полей может быть как бы public, другая - как бы private, переводя на привычный язык ООП. Структуры прекрасно сериализуются и используются в связке с JSON, весьма часто. Сериализации/десериализации подлежат только экспортируемые поля экспортируемых же структур. Если в результируещем JSON мы хотим получить имена атрибутов с маленькой (строчной) буквы, либо получить вовсе некие иные, не соответствующие наименованию исходных полей структуры, имена - для этой цели предусмотрены так называемые JSON tag descriptors. Приведём пример их применения:
Необходимо отметить, что полями структуры могут быть, помимо примитивов, также массивы, срезы, отображения, а также другие, вложенные структуры:
Важное замечание: структурный тип не может содержать поле собственного типа! Формально это правило звучит так: "агрегатное значение не должно содержать само себя".
Данный приём позволяет нам строить связанные списки и деревья. Эти сущности изучает дисциплина, именуемая структуры данных. Имеется немало алгоритмов, использующих указанные техники. Углубление в эту тему в рамках настоящей главы видится избыточным.
Пустые структуры
Как мы с вами выяснили, структуры могут описывать самые различные сущности, и по сему бывают весьма разнообразны по своему составу. Оказывается, порой используются и так называемые пустые структуры. Под пустой структурой понимается структура такого вида:
то есть структура без полей.
В чём примечательность подобной структуры? Главной особенностью является тот факт, что переменная, содержащая пустую структуру занимает в памяти 0 (нуль) байт. Импортируем встроенный пакет unsafe и проверим данное утверждение:
Чем и где это может быть полезно? Да, в общем то, везде, где поможет нам сэкономить память. Обратитесь к своей интуиции! Увы, рассмотреть многие подробности нам пока что не позволяет нехватка знаний. Некоторые полезные приёмы будут рассмотрены позже в главах о методах, интерфейсах и многозадачности. Имея в виду ограниченный объём накопленных нами на данный момент знаний, приведу лишь такой интересный пример: пустые структуры иногда используются в качестве значений в отображениях, в тех случаях, когда программисту могут быть важны ключи а не значения.
Как демонстрирует данный пример, мы создали именованный тип, в основе которого лежит отображение (map), ключом которого является значение типа int, а значением - пустая структура. Целью в данном случае является хранение множества значений типа int, реализуя определение множества как совокупности уникальных неупорядоченных значений. Применение структуры в данном случае служит для экономии памяти, ибо значение ключей здесь не представляет интереса. Также подвергните разбору функцию add, которая служит для установки значений. Обратите внимание и на форму объявления переменной uniqInts. Всякие полезные наблюдения помогут вам овладевать языком, закреплять соответствующие навыки, вырабатывать стиль и приёмы.
Анонимные структуры
В языке Go могут существовать специфические конструкции, которые именуются анонимные структуры. В данном случае вместо декларации типа, объявляется переменная структурного типа с которой можно работать, с некоторыми оговорками. Синтаксически это выглядит так:
Фактически, сигнатурно, s - самая настоящая структура. Однако, s - это переменная, но вовсе не тип. Поэтому инициализация при помощи структурного литерала будет выглядеть так:
Также, поскольку s не является типом, не сработает привычная конструкция вида:
В этом плане возможно лишь прямое присваивание var v = s (создастся копия по значению).
Анонимной структуре может быть без приведения типа присвоено значение "нормальной" структуры, при их сигнатурном совпадении:
В обоих случаях сигнатура структуры - struct { x int; y int }. Внимание! Значение имеет не только тип, но и наименование полей. При несовпадении имён полей даже приведение типов окажется невозможным.
И последнее к вопросу об анонимных структурах. С ними нельзя использовать методы. О методах в контексте анонимных структур мы поговорим в своё время.
Анонимные поля
Говоря о структурах, в языке Go возможен такой фокус, как анонимные поля. И, поскольку имена отсутствуют, будет нетрудным заключение о том, что в такой структуре позволительно лишь одно поле с данными каждого типа (один int, один bool итак далее), ибо именно названия вообще позволяют нам различать однотипные вещи. Выглядеть подобная структура будет как-то так:
Как можно видеть, для доступа к полям вместо привычных имён будут использоваться названия их типов. Объявление "микса" из именованных и неименованных полей допустимо. Неименованные поля всегда закрыты (не экспортируются). Применение методов возможно:
Здесь тип htmlElement описывает общие для всех элементов HTML формы поля и методы. Путём включения, типы button и input получили как нужные поля, так и методы, с ними работающие. Отдельное имя для поля типа htmlElement в данном случае не принципиально, им можно пренебречь. Данный тип нам понадобился в первую очередь для того, чтобы "протащить" в конструкцию нужные методы.
Волшебный местоблюститель
Сравнение структур
Здесь необходимо выделить несколько основных моментов. Во-первых, структуры с разными сигнатурами - принципиально несравниваемы.
Приведение типов T(t1) также невозможно. А вот при совпадении сигнатур возможны варианты. Обратите внимание на применение анонимной структуры - тут даже не потребовалось приведение типов:
Во-вторых, структуры, имеющие в качестве одного или нескольких полей несравниваемые типы (например, срезы) - принципиально несравниваемы.
И, наконец, в-третьих, переменные, представляющие собой структуры одного типа и не содержащие несравниваемых полей, а также сигнатурно идентичные им анонимные структуры, всегда сравниваемы.
Краткое заключение
На данном этапе посчитаем эти сведения о структурах и именованных типах достаточными. Прибегнем к разумному редукционизму. Впереди же нас ждёт продолжение этой важной и интересной темы в главах о методах и интерфейсах, указателях и работе с JSON.
Раунд!
Last updated
Was this helpful?