当前位置:网站首页>Golang reflection operation collation
Golang reflection operation collation
2022-06-24 21:12:00 【The smell of tobacco】
Preface
What is reflex ? We often use it , And this noun is used badly , I won't go into details here .
In short , There is a variable of unknown type , Its type can be obtained through reflection , And can manipulate properties and methods .
Reflection is generally used as a generation tool method , For example, you need a ToString Method , To convert a variable to a string type , If there is no reflection , You need to write : ToStringInt, ToStringBool… wait , Add a method to each type . And with reflection , Just one ToString Method , No matter what type of variable it is , Just throw it to him .
about PHP For this weakly typed language , If you want to call a variable $a Of $b Method , It only needs $a->$b() that will do . And for Golang This strongly typed language can't be so casual . So the following is a brief introduction Golang Application of reflection in .
I hope that after reading the usage of reflection , At least I will not look at the relevant code in the future . Even when you need it, you can do it yourself .
Use
Golang The operations reflected in are defined in the package reflect in . This package mainly includes the following two objects :
reflect.TypeUsed to get the type information of variablesreflect.ValueUsed to operate on the value of a variable
Official document address : reflect.Typereflect.Value
Our use of reflection , It is also based on these two objects .
For the use of reflection , In fact, we usually use it , The following operations are mainly used , Most of the complex operations are hard to use for a hundred years :
- Operation of variable types and attributes
- Operation of variable methods
The following is a simple demonstration based on these two operations .
Operation of variable types and attributes
Get attribute information
In reflection , Type information through reflect.Type Object acquisition .
Access to type
u := struct {
name string
}{
}
// Get reflection object information . Both reflect.Type object
typeOf := reflect.TypeOf(u)
fmt.Println(typeOf)
// The type name of the variable User
fmt.Println(typeOf.Name())
// Get the underlying type of the variable .
// The underlying type of the base type is itself , such as int
// And all custom structures , The underlying types are struct
// All pointers , The underlying types are ptr
// golang All underlying types of are defined in reflect/type.go In file .
// It can be done by reflect.Array Constant for positioning
fmt.Println(typeOf.Kind())
however , Don't be happy too early , If the variable u Change to a pointer : u := &User{}. Using the above method, you can't get the type of the variable . Because the variable content stores the address , Therefore, the address needs to be accessed . The value taking operation method in the reflection package is : reflect.TypeOf(u).Elem(). After getting the value , It's all the same .
Not just pointers , Include : Array, Chan, Map, Ptr, Slice etc. , In fact, all the addresses are stored , Therefore, the capital needs to perform value taking operations .
Be careful , The underlying type here Kind It's very useful , When processing by reflection , There are too many user-defined types to judge , But its underlying type Kind There are only a dozen , Structures of the same underlying type can be treated in the same way .
Structure
type User struct {
Gender int
}
u := struct {
name string
Age int
Address struct {
City string
Country string
} `json:"address"`
User
}{
}
/* Get reflection object information */
typeOf := reflect.TypeOf(u)
// Number of structure fields
fmt.Println(typeOf.NumField())
// For the first 0 A field of information , return StructField object ( There is a description below this object )
// Available fields Name Etc , Include fields Type object
fmt.Println(typeOf.Field(0))
// Get the field according to the variable name
fmt.Println(typeOf.FieldByName("name"))
// For the first 2 The first structure is 0 Elements
fmt.Println(typeOf.FieldByIndex([]int{
2, 0}))
/* StructField Field object contents */
structField := typeOf.Field(2)
// Field name
fmt.Println(structField.Name)
// The accessible package name of the field
// Public fields starting with capital letters , All accessible , Therefore, the value is null
fmt.Println(structField.PkgPath)
// reflect.Type object
fmt.Println(structField.Type)
// The tag string of the field , It's what follows `` character string
// return StructTag object , There are instructions below
fmt.Println(structField.Tag)
// The offset of the field in the memory structure of the structure , byte
fmt.Println(structField.Offset)
// The index of the field in the structure
fmt.Println(structField.Index)
// Anonymous field . In structure Gender It belongs to anonymous field
fmt.Println(structField.Anonymous)
/* StructTag Label content */
tag := structField.Tag
// Gets the tag value of the specified name , If it does not exist , Returns an empty string
fmt.Println(tag.Get("json"))
// And Get The difference is , The second parameter returns whether the tag exists
// Some tags have empty strings that do not behave as undefined , You can use this method to get
fmt.Println(tag.Lookup("json"))
Array
The underlying type of slice is Slice, But the object types stored in different slices are different .
To put it bluntly , An array is actually a pointer to the first address . So to get the contents of the array elements , Just do a value operation .
l := []int{
1, 2}
typeOf := reflect.TypeOf(l)
// empty , Why is this empty? It's said , An array is a pointer
fmt.Println(typeOf.Name())
// slice
fmt.Println(typeOf.Kind())
// Get the type of array element
fmt.Println(typeOf.Elem().Kind())
fmt.Println(typeOf.Elem().Name())
If the array contains a structure , Just use it as a structure
map
m := map[string]int{
"a": 1,
}
typeOf := reflect.TypeOf(m)
// map You can print names without using values map[string]int Don't understand,
fmt.Println(typeOf.Name())
// Object underlying type . map
fmt.Println(typeOf.Kind())
// obtain map Of key The type of
fmt.Println(typeOf.Key().Kind())
// obtain map value The type of
fmt.Println(typeOf.Elem().Kind())
Get attribute value
In reflection , Operations on values , It's all through reflect.Value Object implemented , This object passes through reflect.ValueOf obtain .
meanwhile , be-all Value Object can call Interface Method , To turn it back Interface{} object , Then we can convert through type assertion .
The base type
Value of basic type , GO The corresponding method is provided , It's easy to use .
// Value of foundation type
a := int64(3)
valueOf := reflect.ValueOf(&a)
// Take the foundation type .
// Be careful , If not related , Will report a mistake . You can check the source code
// All plastic surgery , All back to int64, If you need int32, The return value can be obtained and forced to
fmt.Println(valueOf.Int())
//fmt.Println(valueOf.Float())
//fmt.Println(valueOf.Uint())
// ... wait
Structure
If it is a user-defined structure, how to get the value ? this , Always find the base type . Because all custom structures are composed of basic types .
u := struct {
Name string
Age int
}{
"xiao ming", 20}
valueOf := reflect.ValueOf(u)
fmt.Println(valueOf.Field(0).String())
Array
If it's an array ? It's also very simple.
l := []int{
1, 2, 3}
valueOf := reflect.ValueOf(l)
// Modify the value of the specified index
fmt.Println(valueOf.Elem().Index(0))
// Get array length
fmt.Println(valueOf.Elem().Len())
map
Get by reflection Map The value of , What you get is Value object , At the same time, use Value Object . After all Map Of key and value The types are not fixed .
m := map[string]string{
"a": "1",
}
valueOf := reflect.ValueOf(m)
// Gets the value of the specified index
fmt.Println(valueOf.MapIndex(reflect.ValueOf("a")))
// If the value of the specified index does not exist , Will return a kind by Invalid Of Value object
fmt.Println(valueOf.MapIndex(reflect.ValueOf("c")))
// take map size
fmt.Println(valueOf.Len())
// obtain map All of the key, return Value The object list
fmt.Println(valueOf.MapKeys())
// Traverse map Iterator used
mapIter := valueOf.MapRange()
mapIter.Next() // Iterate the pointer line to the next , Returns whether there is still data
fmt.Println(mapIter.Value())
fmt.Println(mapIter.Key())
Attribute assignment
Assignment of base type , reflect.Value Object provides related methods , Are subject to Set start .
Note here , Only variables of pointer type can be assigned . It's easy to understand , The value type is passed by copying when the method is called . Only by passing the pointer can we find the memory address of the original value and modify it .
so , Before we assign values , To be called Kind Method to judge its type , If it is not created through a pointer Value object , Must not be assigned .
All the following assignment operations , Can be linked with the value taking operation .
The base type
a := int64(3)
valueOf := reflect.ValueOf(a)
// This method is used to judge Value Whether the object can be assigned
valueOf.CanSet()
// Because it's a pointer , Therefore, you need to perform a value fetching operation
valueOf.Elem().SetInt(20)
fmt.Println(a)
Structure
The assignment of the structure is the same as the above get attribute value , Use a pointer to get Value object , Then assign a value to its base type .
One thing to pay attention to , Structure only public fields can be assigned by reflection , If assigned to a private field , It throws an exception .
u := struct {
Name string
Age int
}{
"xiao ming", 20}
valueOf := reflect.ValueOf(&u)
valueOf.Elem().Field(0).SetString("xiao hei")
fmt.Println(u)
Array
It is based on Set Methods do provide a lot , But I looked it up , How to assign values to array types ? So I saw this method :
func (v Value) Set(x Value)
This Set Method , Parameters received are Value object ? That would be it . Be careful , Set It is a direct replacement , Instead of adding .
l := []int{
1, 2, 3}
valueOf := reflect.ValueOf(&l)
// Create an array for later assignment
// Be careful , The array type should be the same
setValueOf := reflect.ValueOf([]int{
4, 5})
valueOf.Elem().Set(setValueOf)
fmt.Println(l)
// Modify the value of the specified index
// Through the pointer , Get the value of the specified index , Assign a value
valueOf.Elem().Index(0).SetInt(9)
fmt.Println(l)
map
m := map[string]string{
"a": "1",
}
valueOf := reflect.ValueOf(&m)
// To assign to key Set up
valueOf.Elem().SetMapIndex(reflect.ValueOf("b"), reflect.ValueOf("2"))
fmt.Println(m)
Create a null value Value
In addition to the above assignment operation , There is also a way of not having to judge the object type , By means of New, You can create a null value of the same type Value object , What is returned is a pointer Value type .
The benefits of this operation are , In use , There is no need to judge the object type at all .
a := int64(3)
// Create a content of the same type . It returns a pointer
fmt.Println(reflect.New(reflect.TypeOf(a)).Elem())
Operation of variable methods
Common method
The common method refers to the method not attached to the structure .
func add(a, b int) int {
return a + b
}
func main() {
valueOf := reflect.ValueOf(add)
// constructors parameters
paramList := []reflect.Value{
reflect.ValueOf(2), reflect.ValueOf(3)}
// Call function . Return to one Value Array
retList := valueOf.Call(paramList)
// Get the return value
fmt.Println(retList[0].Int())
}
Structure method
Get method information
Here we need to pay attention to , Structure pointers and objects have different numbers of methods , Specific to see : https://hujingnb.com/archives/348
type User struct {
Name string
}
func (u User) GetName() string {
return u.Name
}
func (u *User) SetName(name string) {
u.Name = name
}
func main() {
u := User{
}
typeOf := reflect.TypeOf(&u)
// Gets the number of methods in the structure . Private methods are not available
fmt.Println(typeOf.NumMethod())
// For the first 0 A way , return Method object . Let's introduce
fmt.Println(typeOf.Method(0))
// Get... Based on the method name , return Method object
fmt.Println(typeOf.MethodByName("GetName"))
/* Method object */
setNameFunc, _ := typeOf.MethodByName("GetName")
// Method name
fmt.Println(setNameFunc.Name)
// Method signature
fmt.Println(setNameFunc.Type)
fmt.Println(setNameFunc.Index)
// The accessible package name of the field . Public method is empty
fmt.Println(setNameFunc.PkgPath)
}
Method call
type User struct {
Name string
}
func (u User) GetName() string {
return u.Name
}
func (u *User) SetName(name string) {
u.Name = name
}
func main() {
u := User{
}
valueOf := reflect.ValueOf(&u)
// Gets the number of methods in the structure . Private methods are not available
fmt.Println(valueOf.NumMethod())
// For the first 0 A way , return Method object . Let's introduce
fmt.Println(valueOf.Method(0))
// Get... Based on the method name , return Method object
fmt.Println(valueOf.MethodByName("GetName"))
/* Method object */
setNameFunc := valueOf.MethodByName("SetName")
// Calling method
params := []reflect.Value{
reflect.ValueOf("xiao ming")}
setNameFunc.Call(params)
// At this point, the value of the object has changed
fmt.Println(u)
// The return value of the receiving method
getNameFunc := valueOf.MethodByName("GetName")
fmt.Println(getNameFunc.Call([]reflect.Value{
}))
}
Original address : https://hujingnb.com/archives/676
边栏推荐
- Does the developer want to change to software testing?
- 传统的IO存在什么问题?为什么引入零拷贝的?
- Difference between map and object
- JMeter installation plug-in, adding [email protected] -Perfmon metric collector listener steps
- Mapstacks: data normalization and layered color layer loading
- database/sql
- When querying the database with Gorm, reflect: reflect flag. mustBeAssignable using unaddressable value
- Microsoft Certification (dynamic 365) test
- Bridging mode -- law firm
- Variable setting in postman
猜你喜欢

Berkeley, MIT, Cambridge, deepmind and other industry leaders' online lectures: towards safe, reliable and controllable AI

The Google File System (GFS) learning notes

Background operation retry gave up; KeeperErrorCode = ConnectionLoss

What does virtualization mean? What technologies are included? What is the difference with private cloud?

Interpreter mode -- formulas for dating

Pytest test framework II

Shrimp skin test surface treated

Agency mode -- Jiangnan leather shoes factory

How to apply agile development ideas to other work

Summary of idea practical skills: how to rename a project or module to completely solve all the problems you encounter that do not work. It is suggested that the five-star collection be your daughter
随机推荐
Shell script
Berkeley, MIT, Cambridge, deepmind et d'autres grandes conférences en ligne: vers une IA sûre, fiable et contrôlable
Camera rental management system based on qt+mysql
IDEA Dashboard
data link layer
Format method and parse method of dateformat class
regular expression
Undo log and redo log must be clear this time
传统的IO存在什么问题?为什么引入零拷贝的?
Where is 5g really powerful? What is the difference with 4G?
Pytest test framework II
Handling of garbled JMeter response data - three solutions
Requests requests for web page garbled code resolution
Physical layer introduction
Time standard and format
[performance tuning basics] performance tuning standards
It was Tencent who jumped out of the job with 26k. It really wiped my ass with sandpaper. It gave me a hand
The JS method parameter passed a number beginning with 0. A magical problem occurred and bothered me for a long time
maptalks:数据归一化处理与分层设色图层加载
Leetcode(146)——LRU 缓存