#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