Публикации - Go

Рефлексия

Рефлексия позволяет работать с типами данных, которые не существуют на момент написания кода, но могут существовать в будущем, когда мы используем существующий пакет с пользовательскими типами данных.

Кроме того, рефлексия может пригодиться, когда необходимо работать с типами данных, которые не реализуют общий интерфейс и, следовательно, имеют необычное или неизвестное поведение. Это не означает плохое или ошибочное поведение, а просто необычное, такое как определяемая пользователем структура.

Наиболее полезными частями пакета reflect являются два типа данных: re­flect.Value и reflect.Type. В частности‚ reflect.Value используется для хранения значений любого типа, тогда как reflect.Type служит для представления Go-типов. Существуют две функции: reflect.TypeOf() и reflect.valueOf(), которые возвращают reflect.Type и reflect.Value соответственно. Обратите внимание, что reflect.TypeOf() возвращает фактический тип переменной‚ и если мы исследуем структуру, то она вернет имя структуры. Поскольку структуры играют ключевую роль в Go, пакет reflect содержит метод reflect.NumField(), предназначенный для перечисления количества полей в структуре, а также метод Field(), позволяющий получать значение reflect.Value определенного поля структуры.

Пакет reflect также определяет тип данных reflect.Kind, который используется для представления определенного типа данных переменной: int, struct и т. д. В документации к пакету reflect перечислены все возможные значения типа данных reflect.Kind. Функция Kind() возвращает вид переменной. Наконец, методы Int() и String() возвращают целое и строковое значения reflect.Value соответственно.

Следующая утилита показывает, как использовать рефлексию для обнаружения внутренней структуры и полей переменной Go-структуры. Введите ее и сохраните как reflection.go:

package main

import (
	"fmt"
	"reflect"
)

type Secret struct {
	Username string
	Password string
}

type Record struct {
	Field1 string
	Field2 float64
	Field3 Secret
}

func main() {
	A := Record{"String value", -12.123, Secret{"Mihalis", "Tsoukalos"}}

	r := reflect.ValueOf(A) // Здесь возвращается значение reflect.Value переменной A.
	fmt.Println("String value:", r.String())

	iType := r.Type() // Используя Type(), мы получаем тип данных переменной — в данном случае переменной A.
	fmt.Printf("i Type: %s\n", iType)
	fmt.Printf("The %d fields of %s are\n", r.NumField(), iType)

    // Цикл for выше позволяет посетить все поля структуры и изучить их характеристики.
	for i := 0; i < r.NumField(); i++ {
        // Оператор fmt.Printf() возвращает имя, тип данных и значение полей.
		fmt.Printf("\t%s ", iType.Field(i).Name)
		fmt.Printf("\twith type: %s ", r.Field(i).Type())
		fmt.Printf("\tand value _%v_\n", r.Field(i).Interface())

		// Проверяем, есть ли в значении другие структуры
		k := reflect.TypeOf(r.Field(i).Interface()).Kind()
		// Чтобы проверить тип данных переменной с помощью строки, нам нужно сначала преобразовать тип данных в string.
		if k.String() == "struct" {
			fmt.Println(r.Field(i).Type())
		}

		// Тоже  что и выше, но с использованием внутреннего значение Struct
		if k == reflect.Struct {
			fmt.Println(r.Field(i).Type())
		}
	}
}

Количество комментариев: 0

Для того, чтобы оставить коментарий необходимо зарегистрироваться