[БЕЗ_ЗВУКА] В видео,
посвященному упаковке-распаковке формата JSON,
мы видели пример, как пакет работает с структурой,
с полями структуры во время выполнения программы.
При этом в Go нет возможности пройтись
по полям структуры просто в цикле, используя оператор for.
Каким образом это реализовано?
На самом деле есть два подхода к работе с динамическими значениями.
Первый подход — это рефлексия,
и рефлексия позволяет оперировать со структурами, либо с какими-то
другими объектами и типами программы прямо во время выполнения.
Давайте посмотрим это на примере.
Итак, у нас есть структура user, для которой вызывается PrintReflect.
Что делает PrintReflect?
PrintReflect просто проходится по всем полям структуры и выводит имя
этого поля, его тип, его значение и теги, если они есть.
Итак, для начала я получаю
объект из пакета рефлексии,
которая представляет собой нашу структуру.
Вот.
После этого я могу, например, получить количество полей,
которые есть у этой структуры, и вывести их на экран.
Дальше я просто начинаю в цикле обходить эти поля.
Я получаю значение этого поля, получаю тип
этого поля и вывожу их всех на экран.
Имя поля, тип поля,
значение этого поля (в данный момент у данной структуры) и тег.
Вот.
Давайте запустим.
[ЗВУК] Итак,
метод структура user имеет четыре поля.
ID типа int, значение 42 и без тега.
RealName string с каким-то значением тега, логин и флаги.
Это простой пример,
который просто выводит какую-то информацию на экран,
но при помощи рефлексии можно делать гораздо больше.
В следующем видео мы рассмотрим
более практическое применение с
присваиванием в поля структуры каких-то значений.
Допустим, у нас есть какой-то формат упаковки данных.
JSON мы брать не будем, он довольно нетривиален в парсинге.
Мы будем парсить просто бинарные данные, упакованные при помощи функции pack.
Эта функция есть во многих языках,
она копирует то значение, которое есть прямо в бинарные данные.
Вот у меня есть вызов perl
функции pack, где я пакую целое число,
строчку, еще один раз целое число.
Строчка запакована в виде длины и потом значения.
Ну и все.
Вот байтовое представление того, что он мне запаковал.
Это int, это длина строки, это сама строка, и еще один int.
И я хочу теперь иметь динамические...
распаковывать такие бинарные данные в структуру.
И вот это я реализую при помощи рефлексии сейчас.
Итак, основная наша функция UnpackReflect.
Что она делает и как она это делает?
Ну, я, конечно же, получаю ридер,
чтобы читать, и из бинарных данных вот data,
которая мне передается, довольно удобно, они по одному байтику смещались в слайсе.
Дальше я получаю
внутреннюю структуру из рефлексии и иду по полям.
Итак, я получаю значение, тип, ну у меня есть тег unpack,
что не надо использовать это для распаковки.
Поэтому если я вдруг встречаю, что в теге есть тег unpack и,
более того, он равен минусу,
то это поле я просто пропускаю, мне оно не нужно.
Дальше у меня есть тип поля.
По нему я сделаю просто switch и реализую
всего лишь два значения, int и строка.
Итак, тип int, то есть kind возвращает внутреннее
тоже представление типа reflect int.
Что я теперь делаю?
Я вижу, что это int.
Значит, мне нужно распаковать четыре байта из того, что есть.
Я создаю временную переменную.
Распаковываю, читаю в нее данные
из буфера при помощи бинарного encoding.
И после этого дела я уже устанавливаю в значение, ValueField,
я устанавливаю
представление через рефлексию тех данных, которые мне нужны.
Отлично.
Int мы распаковали.
Теперь строка.
Строка у нас чуть более сложная структура, она имеет длину и сами данные.
Сначала я распаковываю длину, используя временную переменную,
теперь я создаю slice byte,
для того чтобы в него что-то прочитать.
Читаю в него данные.
И присваиваю внутрь значение.
В значение этого
поля структуры.
А если мне повстречается какой-то неизвестный тип, то я просто ругаюсь.
[ЗВУК] Давайте посмотрим на то, что получилось и как оно заработало.
[ЗВУК] Ура.
У меня была пустая структура, я распаковал в нее значение ID.
RealName я пропустил, из-за того что тег-структура сказала,
не надо это распаковывать.
Распаковал логин и распаковал флаги.
Вот.
Это пример работы с динамическими данными через рефлексию.
Какой минус есть у этого?
У него?
Дело в том, что вы, получается,
должны каждый раз в runtime, во время выполнения работы программы, создавать еще
какие-то дополнительные объекты, объекты пакета рефлексии, и проходиться по ним.
То есть это какие-то вычисления во время работы программы,
то есть оно все-таки не проходит совсем бесплатно.
Есть второй способ для работы с динамическими значениями.
У него есть свои недостатки, и называется он кодогенерация.
Рассмотрим его мы в следующем видео.