В Go большая часть типов, объявляющих переменные, типы и функции в Go, довольно проста.

type Foo struct {
A int
B string
}

var x Foo

func DoSomething(f Foo) {
fmt.Println(f.a, f.B)
}

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

Где я могу использовать Reflect?

Типы

Сначала разберемся с типами. Тип в отражении — это именно то, на что это похоже. Он определяет свойства переменной.

import (
    "fmt"
    "reflect"
)

func main() {
    x := 42
    fmt.Println(reflect.TypeOf(x))
}

Тип reflect.Type определяет методы с информацией о типе переменной.

Существует также метод reflect.Kind, который представляет собой константу, которая говорит, из чего состоит тип — срез, карта, указатель и т. д.

Установка значения

Мы используем функцию reflect.ValueOf для создания экземпляра, представляющего значение переменной.

func main() {
    x := 42
    v := reflect.ValueOf(&x)
    v.Elem().SetInt(100)
    fmt.Println(x)
}
//Output 100

Причина, по которой вам нужно передать указатель на reflect.ValueOf для изменения значения входного параметра, заключается в том, что это точно так же, как и любая другая функция в Go. Кроме того, для всех остальных типов необходимо использовать метод Set.

Если вы не передаете указатель на переменную, вы все равно можете прочитать значение переменной, используя отражение. Но если вы попытаетесь использовать какие-либо другие методы, которые могут изменить значение переменной, вызовы методов вызовут панику.

Вызов метода

Лично я не являюсь поклонником этого подхода, поскольку есть более практичные способы вызова метода.

type Person struct {
    Name string
    Age  int
}

func (p Person) SayHello() {
    fmt.Println("Hello, my name is", p.Name)
}

func main() {
    p := Person{Name: "Alice", Age: 30}
    v := reflect.ValueOf(p)
    method := v.MethodByName("SayHello")
    method.Call(nil)
}

Проверьте, равен ли интерфейс нулю

Если вы хотите проверить, равно ли значение, связанное с интерфейсом, нулю, вы можете сделать это с помощью отражения, используя два метода: IsValid и IsNil.

Func hasNoValue(i interface{}) bool {
iv := reflect.ValueOf(i)
if !iv.isValid() {
   return true
} 
switch iv.Kind() {
  case reflect.Ptr, reflect.Slice, reflect.Map, 
       reflect.Func, reflect.Interface:
    return iv.IsNil()
default: return false
  }
}

Метод isValid возвращает значение true, если reflect.Value содержит что-либо, кроме интерфейса nil.

Сравнение

Одним из наиболее широко используемых методов рефлексии является сравнение.

func main() {
    var x float64 = 3.14
    var y float32 = 3.14

    fmt.Println(reflect.DeepEqual(x, y)) // false

    xv := reflect.ValueOf(x)
    yv := reflect.ValueOf(y)

    fmt.Println(xv.Float() == float64(yv.Float())) // true
}

Если мы попытаемся сравнить их напрямую с помощью оператора ==, мы получим ошибку компиляции.

Вместо этого мы можем использовать отражение для сравнения их значений. Первое сравнение с использованием reflect.DeepEqual сравнивает значения напрямую, но поскольку они имеют разные типы, оно возвращает false.

Второе сравнение использует отражение для получения значений float64 и float32 для x и y соответственно, а затем сравнивает их с помощью оператора ==. Это сравнение возвращает true.

В целом пакет Reflect — это мощный инструмент для проверки объектов и управления ими во время выполнения. Однако отражение может быть более сложным и медленным, чем другие подходы. Кроме того, Go был разработан с учетом параллелизма, а с учетом отражения становится сложнее рассуждать о параллелизме и безопасности потоков.

При этом существует множество других вариантов использования Reflect, таких как запись маршалера данных, создание функций с отражением и т. д. Так что в целом это мощный инструмент, который можно использовать при необходимости.

Похожие истории









Подпишитесь на DDIntel Здесь.

Посетите наш сайт здесь: https://www.datadriveninvestor.com

Присоединяйтесь к нашей сети здесь: https://datadriveninvestor.com/collaborate