Go language combat notes (twenty-four) | Go reflection

Like the Java language, Go also implements runtime reflection, which provides us with the ability to manipulate any type of object at runtime. For example, we can view the specific type of an interface variable, see how many fields a structure has, how to modify the value of a field, and so on.

TypeOf和ValueOf

In Go's reflection definition, any interface is composed of two parts, one is the specific type of the interface, and the other is the value corresponding to the specific type. For example var i int = 3 , because it interface{}can represent any type, the variable ican be converted to interface{}, so the variable can be regarded ias an interface, then the representation of this variable in Go reflection is <Value,Type>, where Value is the value of the variable, 3and the Type variable is the type int.

In Go reflection, the standard library provides us with two types to represent their reflect.Valuesum reflect.Type, and two functions to get the Valuesum of any object Type.

func main() {
	u:= User{"张三",20}
	t:=reflect.TypeOf(u)
	fmt.Println(t)
}

type User struct{
	Name string
	Age int
}
   

reflect.TypeOfYou can get the specific type of any object, and you can see main.Userthis structure type by printing out here . reflect.TypeOfThe function accepts an empty interface interface{}as a parameter, so this method can accept any type of object.

Following the above example, let's see how to get an object in reflection Value.

	v:=reflect.ValueOf(u)
	fmt.Println(v)
   

Like the TypeOffunction, it can also accept any object, you can see the printout as {张三 20}. For the above two kinds of output, Go language also fmt.Printfprovides us with convenient methods through functions.

    fmt.Printf("%T\n",u)
	fmt.Printf("%v\n",u)
   

This example is the same as the output in the previous example.

reflect.Value to primitive type

In the above example, we can reflect.ValueOfturn any type of object into one through a function reflect.Value, so if we want to reverse it, it is actually possible, and it reflect.Valueprovides us with a Intefaceway to help us do this. Continue with the above example:

	u1:=v.Interface().(User)
	fmt.Println(u1)
   

In this way, we are restored to the original Userobject, which can be verified by the printed output. The reason here is because of the reduction in reflection Go's, the subjects were divided into any one reflect.Valueand reflect.Type, while reflect.Valuethey simultaneously hold an object reflect.Valueand reflect.Typeso we can be reflect.Valuea Interfaceway to achieve the reduction. Now we see how to reflect.Valueget the corresponding from one reflect.Type.

	t1:=v.Type()
	fmt.Println(t1)
   

In the above example, by reflect.Valuethe Typemethod can be used to obtain the corresponding reflect.Type.

Get the underlying type of the type

What does the underlying type mean? In fact, the main corresponding types are basic types, interfaces, structures, pointers, etc., because we can typedeclare many new types through keywords. For example, in the above example, uthe actual type of the object is User, but the corresponding underlying type is structthis structure type. Let's verify it.

fmt.Println(t.Kind())
   

It Kindcan be obtained through methods, which is very simple. Of course, we can also use Valueobject Kindmethods. They are equivalent.

"Go Language Practice" reading notes, to be continued, please scan the QR code to follow the flysnow_orgofficial account or website http://www.flysnow.org/ , and read the follow-up notes as soon as possible. If you find it helpful, share it with your friends circle, thank you for your support.

Go language provides the following lowest-level types, as you can see, they are all the most basic.

const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	Array
	Chan
	Func
	Interface
	Map
	Ptr
	Slice
	String
	Struct
	UnsafePointer
)
   

Iterate over fields and methods

Through reflection, we can get the field of a structure type, and also the export method of a type, so that we can understand the structure of a type at runtime, which is a very powerful function.

	for i:=0;i<t.NumField();i++ {
		fmt.Println(t.Field(i).Name)
	}

	for i:=0;i<t.NumMethod() ;i++  {
		fmt.Println(t.Method(i).Name)
	}
   

This example prints out all the field names of the structure and the method of the structure. NumFieldThe method gets how many fields there are in the structure, and then Fieldpasses the index through the method, gets each field in a loop, and then prints out their names.

The same method is similar, so I won't repeat it here.

Modify the value of the field

What if we want to dynamically modify the value of a field during operation? One is that we routinely provide methods or exported fields for us to modify, and the other is to use reflection, which is mainly introduced here.

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

The above is an example of modifying a variable through reflection.

Because the reflect.ValueOffunction returns a copy of the value, the premise is that we pass in the address of the variable to be modified. Secondly, we need to call the Elemmethod to find the value pointed to by this pointer. Finally, we can use the SetIntmethod to modify the value.

There are several important points above to ensure that the value can be modified, and it Valueprovides us with a CanSetmethod to help us determine whether the object can be modified.

We can now update the value of the variable, so how do we modify the value of the structure field? Try it yourself.

Dynamic call method

We can not only call the structure method normally, but also use reflection. To make a reflection call, we must first obtain the method that needs to be called, and then make a parameter call, as shown in the following example:

func main() {
	u:=User{"张三",20}
	v:=reflect.ValueOf(u)

	mPrint:=v.MethodByName("Print")
	args:=[]reflect.Value{reflect.ValueOf("前缀")}
	fmt.Println(mPrint.Call(args))

}

type User struct{
	Name string
	Age int
}

func (u User) Print(prfix string){
	fmt.Printf("%s:Name is %s,Age is %d",prfix,u.Name,u.Age)
}
   

MethodByNameThe method allows us to obtain a method object based on a method name, and then we construct the parameters required by the method, and finally call Callit to achieve the purpose of dynamically calling the method.

We can use the obtained method IsValidto judge whether it is available (existing).

The parameter here is an Valuearray of type, so the required parameters must be ValueOfconverted through functions.

This is the end of the basic introduction of reflection. The next article will introduce some advanced usages, such as obtaining the tag of a field. Commonly used, such as converting a json string to a struct, the tag of the field is used.

Guess you like

Origin blog.csdn.net/qq_32907195/article/details/112463646