создание экземпляра с помощью отражения

#go #reflection

# #Вперед #отражение

Вопрос:

Задана функция с параметром (то есть указателем на структуру) Я хочу создать экземпляр типа этого параметра.

Например, для этой функции:

 func MyFunction(myStruct *MyStruct) {}
 

используя отражение, я хочу создать переменную, которая содержит точно такую же, как x := amp;MyStruct{} будет содержать.

Это пример кода:

 package main

import (
    "fmt"
    "reflect"
)

type MyStruct struct {
}

func main () {
    reflectedFunction := reflect.TypeOf(MyFunction)
    argType := reflectedFunction.In(0)

    reflectedParameter := reflect.New(argType)
    actual := reflectedParameter.Interface()
    fmt.Println(actual)

    expected := amp;MyStruct{}
    fmt.Println(expected)
}

func MyFunction(myStruct *MyStruct) {
}
 

Если вы выполните его, вы увидите, что они содержат другую информацию:

 0xc00000e028 // actual
amp;{} // expected
 

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

Комментарии:

1. посмотрите эту игру play.golang.org/p/Nyuc0mYmgkZ

2. разве это не то же самое

3. Мне удалось получить «то же» значение с помощью Elem(). Интерфейс (), печать возвращает не совсем то же самое, но кажется, что содержимое на самом деле одинаковое (проверено с помощью printf %#v)

4. прочитайте все комментарии и ответьте. Это было предметом обсуждения…

5. @fj123x. Elem().Interface() дает вам тот же тип , однако он по-прежнему является нулевым указателем. В первую очередь вы должны использовать reflect.New правильный тип. Вы не можете получить фактическую переменную *MyStruct динамически, потому что типы определяются во время компиляции, поэтому вам придется довольствоваться интерфейсом, содержащим этот тип.

Ответ №1:

В вашем коде actual это interface{} значение, содержащее a *MyStruct . Как указано в названии и документации, reflectedParameter.Interface() возвращает interface{} .

используя отражение, я хочу создать переменную, которая содержит точно такую же, как x := amp;MyStruct{} будет содержать.

Затем вам нужно будет ввести assert it:

 actual := reflectedParameter.Elem().Interface().(*MyStruct)
 

Комментарии:

1. нет, вам нужен .Elem() . Интерфейс () play.golang.org/p/r5i3tvlD8He

2. @mh-cbon, нет, тебе нужно reflect.New(argType.Elem())

3. @mh-cbon, который по-прежнему будет выдавать значение типа interface{} , а не значение типа amp;MyStruct , как указано в вопросе.

4. Обновленный ответ.

5. @fj123x если вы не можете выполнить утверждение типа, то вы не можете выполнить заявленное вами требование. Типы переменных определяются во время компиляции, во время выполнения могут изменяться только типы значений.

Ответ №2:

reflect.New создает указатель на новое нулевое значение отраженного типа. В вашем примере этот тип уже является a *MyStruct , поэтому значение вашего actual завершается представлением a **MyStruct , как показано в https://play.golang.org/p/Nyuc0mYmgkZ . Использование .Elem() этого параметра снова приводит к правильному типу, но в итоге вы nil получаете указатель (*MyStruct)(nil) .

Вам нужно принять .Elem() , если это первый тип, если вы хотите создать новое значение указателя.

 reflectedParameter := reflect.New(argType.Elem())
 

https://play.golang.org/p/QzwTFUH3HTs

 reflectedFunction := reflect.TypeOf(MyFunction)
argType := reflectedFunction.In(0)

reflectedParameter := reflect.New(argType.Elem())
actual := reflectedParameter.Interface()
fmt.Printf("%#vn", actual)

expected := amp;MyStruct{}
fmt.Printf("%#vn", expected)
 

Который печатает

 amp;main.MyStruct{}
amp;main.MyStruct{}
 

Комментарии:

1. Это не подходит «Я хочу создать переменную, которая содержит точно такую же, какую содержал бы x := amp;MyStruct{}». Это дает interface{} то, что описывает OP, даст a *MyStruct .

2. @Adrian я действительно не согласен с этим аргументом, поскольку, идя по этому пути (отражение), вы будете придерживаться интерфейса

3.@Adrian: это создает *MyStruct типизированное значение, которое вы можете видеть в примере. Передача interface{} fmt.Printf interface{} аргументу или утверждение его сначала не имеет значения.

4.Значение представляет собой значение интерфейса, содержащее *MyStruct . Это не совсем то же самое, что x := amp;MyStruct{} . Это точно так же, как var x interface{} = amp;MyStruct .

5. @Adrian, очевидно, что вы не можете получить типизированное значение без утверждения типа, но основная ошибка в вопросе заключается в том, что пользователь создал **MyStruct