Что делает пакет reflect в Go
Что проверяют
Понимаете ли вы, зачем статически типизированному языку динамический доступ к типам, и знаете ли цену этого доступа. Рефлексию спрашивают, чтобы отличить редкие оправданные случаи от привычки писать на Go как на динамическом языке.
Как отвечать
Пакет reflect позволяет читать и менять значения, тип которых неизвестен на этапе компиляции. Точка входа всегда интерфейсное значение: reflect.TypeOf(x) возвращает описание типа, reflect.ValueOf(x) обёртку над значением, обратно в обычное значение выходят через Interface().
Kind()даёт базовую категорию (структура, срез, указатель),Type()конкретный именованный тип, их регулярно путают;- по структуре ходят через
NumField()иField(i), читают тегиTag.Get("json"), вызывают методы черезMethodByName; - записывать можно только в адресуемое и экспортируемое поле:
type User struct{ Name string }
u := User{}
v := reflect.ValueOf(&u).Elem()
v.FieldByName("Name").SetString("Ann")Где это уместно: сериализаторы и валидаторы по тегам, ORM, внедрение зависимостей, reflect.DeepEqual в тестах. Где неуместно: обычная бизнес-логика, для которой после появления дженериков есть типобезопасное решение.
Цена: проверки уезжают из компиляции в рантайм и превращаются в панику, значения часто уходят в кучу, вызов через рефлексию заметно дороже прямого, а инструменты перестают видеть связи в коде.
Где спотыкаются
Зовут Set на копии и получают панику про неадресуемое значение. Передавать нужно указатель и спускаться через Elem(), иначе CanSet() вернёт false.
Второе: лезут в неэкспортируемое поле. Прочитать его рефлексия даёт, записать нет, и код, который на тестовой структуре работал, падает на боевой.
Третье: считают, что reflect.TypeOf от пустого интерфейса вернёт что-то осмысленное. Он вернёт nil, и следующий вызов метода уронит программу вместо понятной ошибки.