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 i
can be converted to interface{}
, so the variable can be regarded i
as an interface, then the representation of this variable in Go reflection is <Value,Type>
, where Value is the value of the variable, 3
and the Type variable is the type int
.
In Go reflection, the standard library provides us with two types to represent their reflect.Value
sum reflect.Type
, and two functions to get the Value
sum of any object Type
.
func main() {
u:= User{"张三",20}
t:=reflect.TypeOf(u)
fmt.Println(t)
}
type User struct{
Name string
Age int
}
reflect.TypeOf
You can get the specific type of any object, and you can see main.User
this structure type by printing out here . reflect.TypeOf
The 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 TypeOf
function, it can also accept any object, you can see the printout as {张三 20}
. For the above two kinds of output, Go language also fmt.Printf
provides 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.ValueOf
turn 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.Value
provides us with a Inteface
way 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 User
object, 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.Value
and reflect.Type
, while reflect.Value
they simultaneously hold an object reflect.Value
and reflect.Type
so we can be reflect.Value
a Interface
way to achieve the reduction. Now we see how to reflect.Value
get the corresponding from one reflect.Type
.
t1:=v.Type()
fmt.Println(t1)
In the above example, by reflect.Value
the Type
method 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 type
declare many new types through keywords. For example, in the above example, u
the actual type of the object is User
, but the corresponding underlying type is struct
this structure type. Let's verify it.
fmt.Println(t.Kind())
It Kind
can be obtained through methods, which is very simple. Of course, we can also use Value
object Kind
methods. They are equivalent.
"Go Language Practice" reading notes, to be continued, please scan the QR code to follow the
flysnow_org
official 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. NumField
The method gets how many fields there are in the structure, and then Field
passes 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.ValueOf
function 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 Elem
method to find the value pointed to by this pointer. Finally, we can use the SetInt
method to modify the value.
There are several important points above to ensure that the value can be modified, and it Value
provides us with a CanSet
method 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)
}
MethodByName
The 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 Call
it to achieve the purpose of dynamically calling the method.
We can use the obtained method IsValid
to judge whether it is available (existing).
The parameter here is an Value
array of type, so the required parameters must be ValueOf
converted 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.