This is the 28th day of my participation in the August Text Challenge.More challenges in August

Use of reflection

Obtain information about the interface from relect.Value

When reflect.valueof (interface) is executed, you get a variable of type “relect.Value”. You can use its interface () method to get the real content of the interface variable, and then convert it to the original real type. However, we may know the original type or we may not know the original type, so the following two cases are explained.

Given the original type

To cast a given type to its corresponding type, use the Interface method directly and then cast as follows:

RealValue := value.interface ().(known type)Copy the code

Sample code:

package main

import (
	"fmt"
	"reflect"
)

func main(a) {
	var num float64 = 1.2345

	pointer := reflect.ValueOf(&num)
	value := reflect.ValueOf(num)

	// Can be interpreted as a "cast", but need to be aware of, if the type of conversion does not completely match, the direct panic
	// Golang is very strict about the type. The type must be exactly the same
	// The following two values, one is *float64, the other is float64, if the confusion, panic
	convertPointer := pointer.Interface().(*float64)
	convertValue := value.Interface().(float64)

	fmt.Println(convertPointer)
	fmt.Println(convertValue)
}
Copy the code

Running results:

0 xc000098000 1.2345Copy the code

instructions

  1. When converting, if the conversion type does not completely comply with the panic, then directly, the type requirements are very strict!
  2. When converting, distinguish between Pointers and Pointers
  3. That is, reflection can convert a reflection type object back into an interface type variable.

Unknown native type

In many cases, we may not know the specific type, so in this case, what to do? It is necessary for us to get the Filed information through traversal and detection. The example is as follows:

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name string
	Age int
	Sex string
}

func (p Person)Say(msg string)  {
	fmt.Println("hello,",msg)
}
func (p Person)PrintInfo(a)  {
	fmt.Printf("Name: %s, Age: %d, Gender: %s\n",p.Name,p.Age,p.Sex)
}



func main(a) {
	p1 := Person{"lambert".30."Male"}

	DoFiledAndMethod(p1)

}

// Get arbitrary parameters through the interface
func DoFiledAndMethod(input interface{}) {

	getType := reflect.TypeOf(input) // Get the input type
	fmt.Println("get Type is :", getType.Name()) // Person
	fmt.Println("get Kind is : ", getType.Kind()) // struct

	getValue := reflect.ValueOf(input)
	fmt.Println("get all Fields is:", getValue) / / 30 m} {lambert

	// Get the method field
	// 1. Get the reflect.Type of interface, and then iterate through NumField
	// 2. Then get its Field from reflect.Type's Field
	// 3. Get the corresponding value from Field Interface()
	for i := 0; i < getType.NumField(); i++ {
		field := getType.Field(i)
		value := getValue.Field(i).Interface() // Get the ith value
		fmt.Printf("Field name :%s, Field type :%s, field value :%v \n", field.Name, field.Type, value)
	}

	// By reflection, operation method
	// 1. Get reflect.Type of interface and pass NumMethod traverses
	// 2. Reflect.Type's Method gets its Method
	for i := 0; i < getType.NumMethod(); i++ {
		method := getType.Method(i)
		fmt.Printf("Method name :%s, method type :%v \n", method.Name, method.Type)
	}
}
Copy the code

Running results:

get Type is : Person get Kind is : struct get all Fields is: {lambert 30 male} Field Name :Name, field type: String, field value :lambert Field Name :Age, field type :int, field value :30 Field Name :Sex, field type :string, field Name :Age, field type :int, field value :30 Method name :PrintInfo, method type :func(main.person) Method name :Say, method type :func(main.person, string)Copy the code

instructions

It can be seen from the running results that the steps to obtain the specific variables and types of the interface of unknown type are as follows:

  1. Get the reflect.Type of the interface, then iterate through NumField
  2. The reflect.Type Field is then used to retrieve its Field
  3. Finally, the corresponding value is obtained through the Interface() of the Field

It can be seen from the running results that the steps to obtain the method (function) of the interface of unknown type are as follows:

  1. Get the reflect.Type of the interface and iterate through it using NumMethod
  2. Get the corresponding real Method (function) via reflect.Type Method
  3. Finally, take the Name and Type of the result to get the specific method Name
  4. That is, reflection can convert a reflection type object back into an interface type variable.
  5. Struct or struct nesting is the same thing

If it’s a struct, you can use Elem()

tag := t.Elem().Field(0).Tag // Get the Tag attribute defined in the struct
name := v.Elem().Field(0).String() // Get the value stored in the first field
Copy the code
Set the Value of the actual variable with reflect.Value

The Value of reflect.value is obtained by reflect.valueof (X). The Value of the actual variable X can only be modified by reflec.Value if X is a pointer, that is, to modify objects of reflected type, ensure that their values are “addressable”.

Here’s a method:

Elem returns the value contained in interface v or the value pointed to by pointer V. If v is of type other than Interface or PTR, it panics. If v is zero, zero is returned.

package main

import (
	"fmt"
	"reflect"
)

func main(a) {

	var num float64 = 1.2345
	fmt.Println("old value of pointer:", num)

	// Reflect. ValueOf gets reflect.Value in num. Note that the argument must be a pointer to change its Value
	pointer := reflect.ValueOf(&num)
	newValue := pointer.Elem()

	fmt.Println("type of pointer:", newValue.Type())
	fmt.Println("settability of pointer:", newValue.CanSet())

	// reassign
	newValue.SetFloat(77)
	fmt.Println("new value of pointer:", num)

	////////////////////
	// What happens if reflect.valueof's argument is not a pointer?
	//pointer = reflect.ValueOf(num)
	//newValue = pointer.elem () // If it is not a pointer, panic, "panic: reflect: call of reflect.value. Elem on float64 Value"
}
Copy the code

Running results:

Old value of pointer: 1.2345 type of pointer: float64 settability of pointer: true new value of pointer: 77Copy the code

instructions

  1. We pass in a pointer to * float64 and then use pointer.elem () to get the Value to which it points. It must be a pointer.
  2. If the argument passed is not a pointer but a variable, then
    • The object corresponding to the original value obtained by Elem directly panic
    • Use the CanSet method to see if it can be set to return false
  3. CantSet() indicates whether the value can be reset. If true is printed, it can be changed. Otherwise, it cannot be changed.
  4. Reflect.value.elem () retrieves the reflection object corresponding to the original Value. Only the original object can be modified, but the current reflection object cannot be modified
  5. That is, if you want to modify a reflection object, its value must be “addressable”.
  6. Struct or struct nesting is the same thing
The method is called via reflect.Value

This is an advanced usage, so we’ve only looked at several uses of reflection on types and variables, including how to get their value, their type, and how to reset the new value. However, another common and more advanced use in project applications is to reflect a method call. For example, when we want to do a framework project, we need to be able to extend methods at will, or users can customize methods, so how do we extend so that users can customize? The key point is that the user’s custom methods are unknowable, so we can fix that with Reflect.

Call () method:

By reflection, the method is called.

Get the structure object, and then

Sample code:

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name string
	Age int
	Sex string
}

func (p Person)Say(msg string)  {
	fmt.Println("hello,",msg)
}
func (p Person)PrintInfo(a)  {
	fmt.Printf("Name: %s, Age: %d, Gender: %s\n",p.Name,p.Age,p.Sex)
}

func (p Person) Test(i,j int,s string){
	fmt.Println(i,j,s)
}

// How to use reflection to call a method?
// We could have used the structure object. Method name () directly called,
// But for reflection,
// Then you register the method, MethodByName, and invoke mv.call via reflection

func main(a) {
	p2 := Person{"Ruby".30."Male"}
	Reflect.valueof (interface) = reflect.valueof (interface);
	// Get "reflection type object" before proceeding to the next step
	getValue := reflect.ValueOf(p2)

	// 2. Be sure to specify the correct method name
	// Let's look at the call method with no arguments

	methodValue1 := getValue.MethodByName("PrintInfo")
	fmt.Printf("Kind : %s, Type : %s\n",methodValue1.Kind(),methodValue1.Type())
	methodValue1.Call(nil) // No arguments, just write nil

	args1 := make([]reflect.Value, 0) // Create an empty slice
	methodValue1.Call(args1)

	// Method call with arguments
	methodValue2 := getValue.MethodByName("Say")
	fmt.Printf("Kind : %s, Type : %s\n",methodValue2.Kind(),methodValue2.Type())
	args2 := []reflect.Value{reflect.ValueOf("Reflex mechanism")}
	methodValue2.Call(args2)

	methodValue3 := getValue.MethodByName("Test")
	fmt.Printf("Kind : %s, Type : %s\n",methodValue3.Kind(),methodValue3.Type())
	args3 := []reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200),reflect.ValueOf("Hello")}

	methodValue3.Call(args3)
}
Copy the code

Running results:

Name: Ruby, age: 30, gender: male Name: Ruby, age: 30, gender: male Kind: func, Type: func(string) Hello, reflection mechanism Kind: func, Type: func(string) func, Type : func(int, int, string) 100 200 HelloCopy the code

By reflection, call the function.

First of all, we need to make sure that functions are just like ordinary variables. When we talked about the nature of functions in previous chapters, functions can be used as a type of variable, and a reference type. If Fun() is a function, then f1 := Fun is a function. If f1() is called directly, then Fun() is run.

ValueOf() = func (func); Call() = funC (funC);

Sample code:

package main

import (
	"fmt"
	"reflect"
)

func main(a) {
	// Function reflection
	f1 := fun1
	value := reflect.ValueOf(f1)
	fmt.Printf("Kind : %s , Type : %s\n",value.Kind(),value.Type()) //Kind : func , Type : func()

	value2 := reflect.ValueOf(fun2)
	fmt.Printf("Kind : %s , Type : %s\n",value2.Kind(),value2.Type()) //Kind : func , Type : func(int, string)

	// Call the function through reflection
	value.Call(nil)

	value2.Call([]reflect.Value{reflect.ValueOf(100),reflect.ValueOf("hello")})}func fun1(a){
	fmt.Println("I'm the function fun1(), which has no arguments.")}func fun2(i int, s string){
	fmt.Println("I'm a function fun2() that takes arguments...",i,s)
}
Copy the code

instructions

  1. To invoke the corresponding method via reflection, you must first get reflect.valueof (interface) to get reflect.value, and then proceed to the next step
  2. Reflect. Value. This MethodByName MethodByName, you need to specify the exact method of real name, if the error will be directly panic, MethodByName returns the reflect of a function Value. The Value method name.
  3. []reflect.Value, which is the parameter of the final method to be called, can have no or one or more, depending on the actual parameter.
  4. The reflect.value Call method, which will eventually Call the real method, must have the same arguments. If reflect.value. Kind is not a method, it will panic.
  5. It could have been called directly with the object access method, but with reflection, you first register the method, MethodByName, and then Call methodValue.Call with reflection