Unwrapp value za pomocą assercji i reflect

0

Korzystając z pakietu reflect: jaka jest różnica między korzystaniem z reflect.ValueOf().Interface() i zapisywaniem tego do zmiennej typu interface{} a zapisaniem do zmiennej typu interface z pominięciem wywołania .Interface()? Jeżeli dobrze rozumiem, to interfejsy to są wrappery na typy/structury/zmienne - jeżeli zapiszemy coś do interfejsu, to żeby potem z tego wyciągnąć value można to zrobić na dwa sposoby: albo assercją (.(int)) albo reflect.ValueOf - pierwsze zwróci inta, drugie reflect.Value które będzie gdzieś pod spodem jako unsafe.Pointer trzymać adres do tego inta. W poniższym przykładzie:

	intReflected := reflect.ValueOf(interface{}(10))
	fmt.Printf("Type: %T, Value: %v\n", intReflected, intReflected) // reflect.Value, 10
	intAsserted := interface{}(10).(int)
	fmt.Printf("Type: %T, Value: %v\n", intAsserted, intAsserted) // int, 10

	dynamicStruct := reflect.StructOf([]reflect.StructField{
		{
			Name: "Id",
			Type: reflect.TypeOf(0),
		},
		{
			Name: "Name",
			Type: reflect.TypeOf(""),
		},
	})

	instance := reflect.New(dynamicStruct)

	instanceInterfacedByMethod := instance.Interface()
	reflect.ValueOf(instanceInterfacedByMethod).
		Elem().
		FieldByName("Id").
		Set(reflect.ValueOf(interface{}(10)))

	var instanceInterfacedByVarType interface{} = instance

	(instanceInterfacedByVarType.(reflect.Value)).
        Elem().
		FieldByName("Id").
		Set(reflect.ValueOf(interface{}(10))) // it works

	reflect.ValueOf(instanceInterfacedByVarType).
		//Elem(). panic: call of reflect.Value.Elem on struct Value
		FieldByName("Id"). // Type: <invalid reflect.Value>
		Set(reflect.ValueOf(interface{}(10))) // panic: call of reflect.Value.Set on zero Value

Pierwsza assercja i refleksja - jak najbardziej rozumiem. Ale czemu w przypadku gdy korzystam z assercji na reflect.Value to wszystko działa, ale jak już korzystam z reflect.ValueOf to działa (a raczej nie działa) to kompletnie inaczej? Panici są umieszczone w komentarzach w kodzie. I czemu FieldByName jest invalid?

1

W Twoim kodzie instance.Interface() to nie to samo co var instanceInterfacedByVarType interface{} = instance. Pierwsze zwraca zawartość trzymaną w zmiennej typu reflect.Value jako interfejs. Drugie opakowuje zmienną typu reflect.Value w interfejs.

reflect.ValueOf wytwarza nowe reflect.Value. Wytworzyłeś nowe reflect.Value, które opakowuje inne reflect.Value. Metoda reflect.Value.Elem wymaga, by reflect.Value był opakowaniem dla wskaźnika albo interfejsu, z w Twoim wypadku jest dla struktury trzymanej przez wartość. Z kolei FieldByName("Id") stwierdzi, że type reflect.Value nie ma pola Id.

1 użytkowników online, w tym zalogowanych: 0, gości: 1