Учебное пособие по отражениям: строка запроса для структурирования синтаксического анализатора в Go.
Когда нам нужно работать с переменными во время выполнения, используя информацию, которой не было на момент написания программы, или нам может потребоваться создать переменные во время выполнения для тестовых случаев, в этих ситуациях нам может потребоваться отражение. Отражение станет вашим незаменимым инструментом, когда вы работаете с универсальным дизайном.
Вкратце, Reflections позволяет исследовать, изменять и создавать переменные, структуры и функции во время выполнения программы.
В этом руководстве мы планируем создать собственный запрос GET для синтаксического анализатора структуры, чтобы понять, как можно использовать отражения в go lang.
Прежде чем мы начнем, нам нужно узнать, как найти тип переданного interface{}
type.
Если мы посмотрим на функцию выше, мы принимаем входные данные как динамический тип interface{}
в go. Простое замечание: если вы найдете библиотеку, которая использует interface{}
, она наверняка может использовать отражения в качестве своего внутреннего механизма.
reflect.TypeOf(d)
создает объектreflect.Type
сKind
в качестве типа переменной, переданной в функцию.td.Kind()
получает тип переменной. Тип можно сравнить с константами, присутствующими в пакете отражения, то есть со всеми базовыми типами, доступными в go like;Int, Uint, Func, Interface, Map, Ptr
и т. Д.
Когда мы когда-либо хотим работать с типами, мы используем reflect.TypeOf
для преобразования в reflect.Type
, а затем выполняем с ними различные операции, например, мы можем создать новую переменную с помощью reflect.New
, которая вернет переменную с заданным типом.
HTTP СЕРВЕР
Теперь давайте начнем с создания базового http
сервера, который будет служить точкой для обработки запросов GET. Это просто;
http.HandleFunc("/map-it", HandleGetMapping) http.ListenAndServe(":5000", nil)
Где может выглядеть функция HandleGetMapping
;
// HandleGetMapping handles get request func HandleGetMapping(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "got %v", req.URL.Query().Get("hello")) }
Давайте создадим наш тип структуры с with, который будет действовать как структура-держатель для нашего запроса на получение.
// Article data type type Article struct { Title string `mapper:"title" json:"title"` Body string `mapper:"body" json:"body"` JSON string `mapper:"json" json:"json"` }
Здесь тип тега mapper
- это наш настраиваемый тип, который мы будем использовать позже для отображения ключа запроса в структуру. т.е.
http://localhost:8080/map-it?title=title&body=bo&json={"A":"a"}
отображается в приведенную выше структуру.
ФУНКЦИЯ КАРТИРОВАНИЯ
Итак, давайте создадим еще одну функцию с именем MapIt
, которая принимает указатель interface{}
и сопоставляет предоставленную структуру с данными из запроса получения.
Взглянув на приведенную выше функцию, мы можем это увидеть;
dhVal := reflect.ValueOf(d)
создает значение, отражающее тип, с помощью которого мы можем установить или получить значение. Основное различие междуreflect.TypeOf
иreflect.ValueOf
заключается в том, что с помощью значения варианта мы можем получить или установить значение переменной, но с помощьюTypeOf
мы можем получить только информацию о типе значения.- Поскольку мы передаем ссылку на значение в
d
, нам нужно отменить ссылку на указатель, чтобы получить / установить в него значение, что выполняется с помощьюdType.Elem()
. Но посколькуdType.Elem()
- это структура, мы можем получить количество полей, присутствующих в структуре, и поместить его в цикл, используя функциюNumField
. - Чтобы получить значение тега, присутствующее в поле структуры
reflect.StructField
, мы можем использовать методTag
structsGet
для получения ключа. - Наконец, функция
result.SetString
используется для установки строкового значения, которое мы получили отreq.URL.Query().Get(key)
. Для установки различных других типов данных мы можем:SetInt
,Set
функции, присутствующие в поле структуры.
Давайте воспользуемся этой функцией, чтобы завершить нашу HandleGetMapping
функцию, которая выглядит следующим образом (просто базовый обработчик, здесь ничего особенного);
- Здесь мы используем функцию
MapIt
, определенную ранее, и передаем на нее ссылку во входную структуру. - Мы используем
json.Marshal
для преобразования отображаемой структуры вjsonData
для предоставления ответа пользователю.
НАКОНЕЦ
Итак, после объединения всех функций весь наш сервер выглядит так:
После запуска этого сценария мы можем найти это;
http://localhost:5000/map-it?title=Awesome%20Title&body=sample%20body&json={%22A%22:%22a%22}
отображается в структуру и маршалируется обратно в строку на выходе;
{ "title": "Awesome Title", "body": "sample body", "json": "{\"A\":\"a\"}" }
Итак, таким образом мы можем посмотреть, как мы сопоставили параметр запроса получения с структурой перехода с помощью отражения. Это всего лишь базовый пример использования отражения. Для более сложных примеров мы можем посмотреть; json.Marshal
функция, которая использует отражение для преобразования структуры в строковое значение json.
Для более полного кода с использованием gin
framework вы можете заглянуть в https://github.com/dipeshdulal/learning-golang/tree/master/structparser
Вот и все. Удачного кодирования.
Подробнее об отражениях читайте здесь;
Https://medium.com/capital-one-tech/learning-to-use-go-reflection-part-2-c91657395066
Следуйте за мной на GitHub: https://github.com/dipeshdulal
Для получения дополнительных образцов по основам проверки голанга; Https://github.com/dipeshdulal/learning-golang
Аригату あ り が と う