Hello everyone, my name is Xie Wei, I am a programmer.
We will continue to update the learning content of the built-in library in the near future. The main references are official documentation and source code.
The topic of this section is reflection — the ability of a type to use some mechanism to describe and detect its own behavior, simply to obtain the type and value of data.
So the core of reflection has two aspects: type and value.
Outline:
- Self – summed up the use of reflection
- The official use of reflection
- What you learned
Self – summed up the use of reflection
Since the use of reflection has two aspects, there are two aspects of everyday coding: getting the type and getting the value
The most basic usage is shown below, and is used with structures.
- reflect.TypeOf
- reflect.ValueOf
var number int
number = 1
fmt.Println(reflect.TypeOf(number), reflect.ValueOf(number))
>> int 1
Copy the code
type numberExample int
var numberOther numberExample
numberOther = 2
fmt.Println(reflect.TypeOf(numberOther), reflect.ValueOf(numberOther), reflect.ValueOf(numberOther).Kind())
>> main.numberExample 2 int
Copy the code
You can see how to get data types, and you can see the difference between TypeOf and Kind. TypeOf gets basic data types and types defined as type. Kind fetches the underlying basic data types, but does not include types defined as type.
But the most common use of reflection is with structures. Structures in Go are collections of data of various data types, and can have their own methods.
The structure definition, as well as the tag, plays a role in the serialization and deserialization between the structure and JSON.
Define the following structure:
type Info struct {
Name string `json:"name"`
Age interface{} `json:"age"`
Prince float32 `json:"prince"`
}
type Groups struct {
ID uint `json:"id"`
Name string `json:"name"`
Count int `json:"count"`
CanFly bool `json:"can_fly"`
GroupIDs []int `json:"group_ids"`
GroupName []string `json:"group_name"`
Info `json:"info"`
}
Copy the code
Two structures are defined, and the corresponding fields are also declared with tags.
Initialization:
// An anonymous structure that defines global variables
var globalValue struct {
groups Groups
}
var valid struct {
tag string
value Model
}
func init(a) {
globalValue.groups = Groups{
ID: 1,
Name: "xieWei",
Count: 12,
CanFly: false,
GroupIDs: []int{100.200.300.400},
GroupName: []string{"what"."how"."when"."why"},
Info: Info{
Name: "XieXiaoLu",
Age: 20,
Prince: 1.2345,
},
}
valid.tag = "xieWei"
valid.value = Model{
ID: 1,
Count: 2000,
Name: "Golang",}}Copy the code
Define two methods for the structure, the main operation type and the value.
func (g Groups) TypeHandler(a){}func (g Groups) ValueHandler(a){}Copy the code
A reflection operation on a structure gets the type, value, and tag of the structure’s attributes.
Think for a moment about what the author would design to get an attribute’s type, value, and tag.
Get attributes, traverse attributes, number of attributes, get attributes by index
func (g Groups) TypeHandler() {}Copy the code
func (g Groups) TypeHandler(a) {
typeGroups := reflect.TypeOf(g)
name := typeGroups.Name()
fmt.Println("Name: ", name, "Kind", typeGroups.Kind())
for i := 0; i < typeGroups.NumField(); i++ {
filed := typeGroups.Field(i)
fmt.Println(filed.Name, "\t", filed.Tag, "\t", reflect.ValueOf(filed), "\t", filed.Type)
}
for i := 0; i < typeGroups.NumField(); i++ {
filedByIndex := typeGroups.FieldByIndex([]int{i})
filedByName, _ := typeGroups.FieldByName(filedByIndex.Name)
fmt.Println(filedByIndex, filedByIndex.Name, filedByIndex.Type)
fmt.Println(filedByName, filedByName.Name, filedByName.Type)
}
for i := 0; i < typeGroups.NumMethod(); i++ {
method := typeGroups.Method(i)
fmt.Println(method.Name, method.Type)
}
}
Copy the code
Method of manipulating structure:
for i := 0; i < typeGroups.NumMethod(); i++ {
method := typeGroups.Method(i)
fmt.Println(method.Name, method.Type)
}
Copy the code
The operating value:
func (g Groups) ValueHandler() {}Copy the code
func (g Groups) ValueHandler(a) {
valueGroup := reflect.ValueOf(g)
fmt.Println(valueGroup.NumField(), valueGroup.NumMethod(), valueGroup, reflect.ValueOf(&g).Elem())
for i := 0; i < valueGroup.NumField(); i++ {
field := valueGroup.Field(i)
fmt.Println(field, field.Type(), field.Kind())
}
method := valueGroup.MethodByName("TypeHandler")
fmt.Println(method, method.Kind(), method.Type())
for i := 0; i < valueGroup.NumMethod(); i++ {
method := valueGroup.Method(i)
fmt.Println(method.Type())
}
ref := reflect.ValueOf(&g).Elem()
fmt.Println(ref.FieldByName("Name"), ref.Field(0))}Copy the code
Why is this operation?
Property, value, traversal property, traversal value
The document
Why do you do that?
That of course depends on the definition of Type, which is an interface.
type Type interface {
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
Kind() Kind
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
NumField(a) int
}
Copy the code
You can see how to manipulate the type of the structure property.
The definition of a Value is a structure. No properties, methods.
type Value struct {
// contains filtered or unexported fields
}
func (v Value) Field(i int) Value
func (v Value) FieldByIndex(index []int) Value
func (v Value) FieldByName(name string) Value
func (v Value) FieldByNameFunc(match func(string) bool) Value
func (v Value) Method(i int) Value
func (v Value) MethodByName(name string) Value
func (v Value) NumField(a) int
func (v Value) NumMethod(a) int
Copy the code
Sometimes, we can’t remember the API and don’t know which methods to use. What do we do?
Let’s take a structure, right?
- So just to review the definition of a structure, what is a structure?
- attribute
- How do I get attributes? By index, by name
- Number of attributes?
- The type of the property? The name?
- methods
- Method name
- How to get methods
- How do I call a method?
- Number of methods
As you can see, strictly speaking, the knowledge of the structure is property (private, public), method (call, declaration).
Therefore, the author’s underlying structure definition is also about these operations.
So far, we have not operated on the tag of the structure.
For example, the following structure definition:
type Model struct {
ID uint `xieWei:"number,max=10,min=1"`
Name string `xieWei:"string"`
Count int `xieWei:"number,max=100,min=1"`
CanFly bool `xieWei:"bool,default=false"`
}
Copy the code
We often see the use of these tags in GIN or GORM.
For example: Gin
type PostParam string {
ID uint `form:"id" binding:"required,omitempty"`
Name string `form:"name" binding:"required"`
Number int `form:"number" binding:"required,eq=1|eq=2"`
}
Copy the code
Whether the field is required, whether the null value is omitted, and the value range are specified according to the tag above
Another example: GORM defines database tables
type Student struct {
Name string `gorm:"type:"varchar,column:name" json:"name"`
Number int `gorm:"type:"integer,column:number" json:"number"`
}
Copy the code
Table column name (tag);
How does that work?
Answer: Reflection
By reflection, we get the tag of the structure, which is a string, and we do operations on the string, like split operations, get the type and so on.
For example, we need to check the type of the structure’s properties ourselves.
func (m Model) Handler(name string) bool {
typeModel := reflect.TypeOf(m)
if tag, ok := typeModel.FieldByName(name); ok {
if ok := strings.HasPrefix(string(tag.Tag), valid.tag); ok {
//fmt.Println(validTagList[0])
validTagList := strings.FieldsFunc(string(tag.Tag), func(r rune) bool {
return r == ', ' || r == '"'
})
switch validTagList[1] {
case "number":
{
fmt.Println(validTagList[1:)}case "string":
fmt.Println(validTagList[1:)case "bool":
fmt.Println(validTagList[1:)}}else {
return false}}return false
}
>>
[number max=10 min=1]
[string]
[number max=100 min=1]
[bool default=false]
[number min=1 max=1000]
Copy the code
Perform subsequent operations.
The overall idea is:
- Gets the tag for the structure attribute
- Operate on tag as a string
- Of course, their own calibration, the best structured, such as
valid:number,max=10,min=1
, unified according to such operation, convenient perhaps analysis.
Conclusion:
Reflect is an application’s ability to check for its own type. Use the reflect library to get the type and value of a variable, structure, and set the corresponding value.
Reflection on structures is one of the more central uses of Reflect.
How to operate:
- A structure has properties (public and private) and methods
- Reflection retrieves properties, either by traversal, by index value, or by property name
- Reflection retrieves methods, either by variable or by method name
What did you learn?
Postscript: learning, always want to master all knowledge in one breath, actually not scientific, the first time to see, you may only master 10%, the correct approach, should be repeatedly see, especially when you need to solve the problem. Finally, be sure to integrate your own thinking, just painting and writing can give you more memory information.