reflex
Like other languages, the reflection of Go language also refers to the ability of a computer program to access, detect and modify its own state or behavior when it is running.
In the reflect package, it defines an interface and a structure, namely reflect Type interface and reflect Value structure, which provides many functions to obtain the type information stored in the interface.
- reflect.Type interface: mainly provides type related information
- reflect.Value structure: it mainly provides information about values, and can obtain or even change the value of type.
The reflect package provides two basic functions about reflection to obtain the above interfaces and structures:
func TypeOf(i interface()) Type func ValueOf(I interface()) Value
Of which:
- TypeOf() function: used to extract the type information of a value in an interface. Since its input parameter is an empty interface {}, when calling this function, the argument will be converted to interface {} type first. In this way, the type information, method set and value information of the argument are stored in the interface {} variable.
- ValueOf() function: returns a structure variable, including type information and actual value.
The detailed schematic diagram is as follows:
Three principles of reflection
In Go language, reflection has three principles:
- Reflection can convert an interface type variable to a reflection type object“
- Reflection can convert a reflection type object to an interface type variable“
- If you want to modify the reflection type object, its value must be writable
Convert "interface type variable" to "reflection type object"
Reflection is a mechanism for checking Type and Value pairs stored in interface variables. There are two types in the reflect package: Type and Value. These two types give us access to the contents of an interface variable.
In addition, there are two simple functions, reflect Typeof() and reflect Valueof() can retrieve the reflection of an interface value Type and reflect Value section. Examples are as follows:
import ( "fmt" "reflect" ) func main() { var x float64 = -3.151592653 fmt.Println("Type:", reflect.TypeOf(x)) v := reflect.ValueOf(x) fmt.Println("Value:", v) fmt.Println("Type:", v.Type()) fmt.Println("is float64: ", v.Kind() == reflect.Float64) fmt.Println("Value:", v.Float()) }
After running, we will get the following results.
In the above code, we first define a variable of float64, and then assign it to reflect Typeof (x) function. When we call this function, x will be saved to the empty interface, and then the empty interface will be passed as a parameter, reflect Typeof unpacks the empty interface and restores the type information.
Of course, reflect Valueof (x) can also restore the value, and reflect The variable type obtained by valueof can also be operated with methods. For example, get types, values, and comparison types.
Convert "reflection type object" to "interface type variable"
This is just the opposite of the above. Similar to physics, there is matter, there is antimatter.
In Go language, reflection can also create its own negative type of objects. According to reflect For a variable of type value, you can use the interface() method to restore the value of its interface type. Moreover, this method will package and fill the type and value information into an interface variable, and then return. It is defined as follows:
//definition func (v Value) Interface() interface{} //example func main() { var name interface{}="liyuanjing" x :=reflect.TypeOf(name) y :=reflect.ValueOf(name) //From interface variable to reflection object fmt.Printf("From interface variable to reflection object: Type The object type is%T \n",x) fmt.Printf("From interface variable to reflection object: Value The object type is%T \n",y) //From reflection object to interface variable z :=y.Interface() fmt.Printf("From reflection object to interface variable: the type of the new object is%T Value is%v \n",z,z) }
After running, the console output effect is as follows:
"Reflection type object" modification (the value must be "writable")
When using reflect Typeof() function and reflect If the pointer of the interface variable is not passed in the valueof() function, the variable in the reflection world is always a copy in the real world. Modifying the reflection object cannot be reflected in the real world.
It should be noted that:
- Reflection objects that are not created by receiving variable pointers do not have "Writeability"
- Whether it has "writability" can be determined by CanSet() method
- Modifying an object that does not have "Writeability" is meaningless and considered illegal, so an error will be reported.
If you need to make reflection writable, you need to do this:
- When you create a reflection object, you pass in a pointer to the variable
- Use the Elem() method to return the data pointed to by the pointer.
Writability judgment example:
func main() { var name string = "liyuanjing" x := reflect.ValueOf(&name) fmt.Println("x The writability of is:", x.CanSet()) y := x.Elem() fmt.Println("y The writability of is:", y.CanSet()) }
After running, you will find that x is not writable, and y is writable because of the Elem() method.
After knowing how to use the Writeability of objects in the reflective world, it's time to learn how to update objects for modification.
In the reflected Value object, there are multiple methods starting with the word Set to reset the Value of the corresponding type. For example:
func (v Value) SetBool(x bool) func (v Value) SetBytes(x []byte) func (v Value) setRunes(x []rune) func (v Value) SetComplex(x complex128) func (v Value) SetFloat(x float64) func (v Value) SetInt(x int64)
These methods are all entries for modifying values. For example, an example of updating values through the reflection object SetInt() method is as follows:
func main() { var num int = 30 fmt.Println("The original value is:", num) x := reflect.ValueOf(&num) y := x.Elem() y.SetInt(500) fmt.Println("After updating by reflecting objects, num The true value of is:", num) }
After running, the effect is as follows: