通过代码学习 reflection, 直接上代码
代码如下:
```go
package main
import (
"fmt"
"reflect"
)
type Student struct {
name string
age int ``
}
func (s *Student) Study() {
fmt.Print("Studying reflection...")
}
func (s Student) Learn() {
fmt.Print("Learning reflection...")
}
type MyStudent Student
func main() {
var obj interface{}
//int
obj = 1
ShowObjInfo(obj)
//*int
value := 2
ShowObjInfo(&value)
//string
obj = "hello world!"
ShowObjInfo(obj)
//*string
str := "hello world!"
ShowObjInfo(&str)
//map
obj = map[string]string{"key1": "value1", "key2": "value2"}
ShowObjInfo(obj)
//slice
obj = []string{"eagle", "guo"}
ShowObjInfo(obj)
//type alias
type MyInt int
obj = MyInt(1)
ShowObjInfo(obj)
obj = MyStudent{name: "eagle"}
ShowObjInfo(obj)
//chan
obj = make(chan Student)
ShowObjInfo(obj)
//struct
obj = Student{name: "eagle", age: 10}
ShowObjInfo(obj)
//*struct
obj = &Student{name: "eagle", age: 10}
ShowObjInfo(obj)
// func
obj = func(i Student) {}
ShowObjInfo(obj)
// reflect.Value and reflect.rType itself
ShowObjInfo(reflect.TypeOf(obj))
ShowObjInfo(reflect.ValueOf(obj))
fmt.Println("== 通过反射修改对象=====")
var num float64 = 1.2345
fmt.Println("value to modify of pointer:", num)
// 通过reflect.ValueOf获取num中的reflect.Value,注意,参数必须是指针才能修改其值
//pointer := reflect.ValueOf(num) // note the difference better num and &num
pointer := reflect.ValueOf(&num)
newValue := pointer.Elem()
fmt.Println("settability of pointer:", pointer.CanSet())
fmt.Println("settability of newValue:", newValue.CanSet())
// 重新赋值
newValue.SetFloat(77)
fmt.Println("type of newValue:", newValue.Type())
//newValue.SetInt(30) //panic
switch xx := newValue.Interface().(type) {
default:
fmt.Println("new value of pointer:", xx)
fmt.Printf("new value of pointer type: %T\n", xx)
}
student2 := Student{name: "eagle", age: 10}
switch xx := reflect.ValueOf(student2).Interface().(type) {
default:
fmt.Println("value of student2 is", xx)
fmt.Printf("type of student2 is %T\n", xx)
}
fmt.Println("new value of pointer:", num)
}
func ShowObjInfo(obj interface{}) {
t := reflect.TypeOf(obj)
v := reflect.ValueOf(obj)
fmt.Printf("====================%v======================\n", t)
fmt.Printf("type is %v, value is %v\n", t, v)
//fmt.Printf("kind is %v\n", t.Kind()) //both methods are ok to get kind
fmt.Printf("kind is %v\n", v.Type().Kind())
fmt.Printf("the name of the type is %v\n", t.Name())
fmt.Printf("the full name of the type is %v\n", t.String())
fmt.Printf("the size of the type is %v\n", t.Size())
switch t.Kind() {
case reflect.Ptr:
p := v.Elem()
typeOfT := p.Type()
fmt.Printf("kind is %v, type is %v\n", p.Kind(), typeOfT)
switch p.Kind() {
case reflect.Struct:
if p.NumField() > 0 {
fmt.Println("-- fields:")
}
for i := 0; i < p.NumField(); i++ {
fmt.Printf(" -- %v: %v %v = %v\n", i, typeOfT.Field(i).Name, typeOfT.Field(i).Type, reflect.ValueOf(p.Field(i)).Interface())
}
if typeOfT.NumMethod() > 0 {
fmt.Println("-- methods :")
for i := 0; i < typeOfT.NumMethod(); i++ {
fmt.Printf(" -- %v: name: %v, %v\n", i, typeOfT.Method(i).Name, typeOfT.Method(i).Type)
}
}
if t.NumMethod() > 0 {
fmt.Println("-- methods:")
for i := 0; i < t.NumMethod(); i++ {
fmt.Printf(" -- %v: name: %v, %v\n", i, t.Method(i).Name, t.Method(i).Type)
}
}
}
case reflect.Struct:
fmt.Printf("the num of fields is %v and the mum of method is %v \n", t.NumField(), t.NumMethod())
if t.NumField() > 0 {
fmt.Println("-- fields:")
}
for i := 0; i < t.NumField(); i++ {
fmt.Printf(" -- %v: %v %v = %v\n", i, t.Field(i).Name, t.Field(i).Type, reflect.ValueOf(v.Field(i)).Interface())
}
if t.NumMethod() > 0 {
fmt.Println("-- methods:")
for i := 0; i < t.NumMethod(); i++ {
fmt.Printf(" -- %v: name: %v, %v\n", i, t.Method(i).Name, t.Method(i).Type)
}
}
default:
fmt.Printf("the mum of method is %v \n", t.NumMethod())
if t.NumMethod() > 0 {
fmt.Println("-- methods")
for i := 0; i < t.NumMethod(); i++ {
fmt.Printf(" -- %v: name: %v, %v\n", i, t.Method(i).Name, t.Method(i).Type)
}
}
}
}
```
输出如下
```bash
====================int======================
type is int, value is 1
kind is int
the name of the type is int
the full name of the type is int
the size of the type is 8
the mum of method is 0
====================*int======================
type is *int, value is 0xc00000a0d8
kind is ptr
the name of the type is
the full name of the type is *int
the size of the type is 8
kind is int, type is int
====================string======================
type is string, value is hello world!
kind is string
the name of the type is string
the full name of the type is string
the size of the type is 16
the mum of method is 0
====================*string======================
type is *string, value is 0xc000042220
kind is ptr
the name of the type is
the full name of the type is *string
the size of the type is 8
kind is string, type is string
====================map[string]string======================
type is map[string]string, value is map[key1:value1 key2:value2]
kind is map
the name of the type is
the full name of the type is map[string]string
the size of the type is 8
the mum of method is 0
====================[]string======================
type is []string, value is [eagle guo]
kind is slice
the name of the type is
the full name of the type is []string
the size of the type is 24
the mum of method is 0
====================main.MyInt======================
type is main.MyInt, value is 1
kind is int
the name of the type is MyInt
the full name of the type is main.MyInt
the size of the type is 8
the mum of method is 0
====================main.MyStudent======================
type is main.MyStudent, value is {eagle 0}
kind is struct
the name of the type is MyStudent
the full name of the type is main.MyStudent
the size of the type is 24
the num of fields is 2 and the mum of method is 0
-- fields:
-- 0: name string = eagle
-- 1: age int = 0
====================chan main.Student======================
type is chan main.Student, value is 0xc000046060
kind is chan
the name of the type is
the full name of the type is chan main.Student
the size of the type is 8
the mum of method is 0
====================main.Student======================
type is main.Student, value is {eagle 10}
kind is struct
the name of the type is Student
the full name of the type is main.Student
the size of the type is 24
the num of fields is 2 and the mum of method is 1
-- fields:
-- 0: name string = eagle
-- 1: age int = 10
-- methods:
-- 0: name: Learn, func(main.Student)
====================*main.Student======================
type is *main.Student, value is &{eagle 10}
kind is ptr
the name of the type is
the full name of the type is *main.Student
the size of the type is 8
kind is struct, type is main.Student
-- fields:
-- 0: name string = eagle
-- 1: age int = 10
-- methods :
-- 0: name: Learn, func(main.Student)
-- methods:
-- 0: name: Learn, func(*main.Student)
-- 1: name: Study, func(*main.Student)
====================func(main.Student)======================
type is func(main.Student), value is 0x4c5730
kind is func
the name of the type is
the full name of the type is func(main.Student)
the size of the type is 8
the mum of method is 0
====================*reflect.rtype======================
type is *reflect.rtype, value is func(main.Student)
kind is ptr
the name of the type is
the full name of the type is *reflect.rtype
the size of the type is 8
kind is struct, type is reflect.rtype
-- fields:
-- 0: size uintptr = 8
-- 1: ptrdata uintptr = 8
-- 2: hash uint32 = 3604702347
-- 3: tflag reflect.tflag = 2
-- 4: align uint8 = 8
-- 5: fieldAlign uint8 = 8
-- 6: kind uint8 = 51
-- 7: alg *reflect.typeAlg = &{<nil> <nil>}
-- 8: gcdata *uint8 = 0x51f99a
-- 9: str reflect.nameOff = 36918
-- 10: ptrToThis reflect.typeOff = 0
-- methods:
-- 0: name: Align, func(*reflect.rtype) int
-- 1: name: AssignableTo, func(*reflect.rtype, reflect.Type) bool
-- 2: name: Bits, func(*reflect.rtype) int
-- 3: name: ChanDir, func(*reflect.rtype) reflect.ChanDir
-- 4: name: Comparable, func(*reflect.rtype) bool
-- 5: name: ConvertibleTo, func(*reflect.rtype, reflect.Type) bool
-- 6: name: Elem, func(*reflect.rtype) reflect.Type
-- 7: name: Field, func(*reflect.rtype, int) reflect.StructField
-- 8: name: FieldAlign, func(*reflect.rtype) int
-- 9: name: FieldByIndex, func(*reflect.rtype, []int) reflect.StructField
-- 10: name: FieldByName, func(*reflect.rtype, string) (reflect.StructField, bool)
-- 11: name: FieldByNameFunc, func(*reflect.rtype, func(string) bool) (reflect.StructField, bool)
-- 12: name: Implements, func(*reflect.rtype, reflect.Type) bool
-- 13: name: In, func(*reflect.rtype, int) reflect.Type
-- 14: name: IsVariadic, func(*reflect.rtype) bool
-- 15: name: Key, func(*reflect.rtype) reflect.Type
-- 16: name: Kind, func(*reflect.rtype) reflect.Kind
-- 17: name: Len, func(*reflect.rtype) int
-- 18: name: Method, func(*reflect.rtype, int) reflect.Method
-- 19: name: MethodByName, func(*reflect.rtype, string) (reflect.Method, bool)
-- 20: name: Name, func(*reflect.rtype) string
-- 21: name: NumField, func(*reflect.rtype) int
-- 22: name: NumIn, func(*reflect.rtype) int
-- 23: name: NumMethod, func(*reflect.rtype) int
-- 24: name: NumOut, func(*reflect.rtype) int
-- 25: name: Out, func(*reflect.rtype, int) reflect.Type
-- 26: name: PkgPath, func(*reflect.rtype) string
-- 27: name: Size, func(*reflect.rtype) uintptr
-- 28: name: String, func(*reflect.rtype) string
====================reflect.Value======================
type is reflect.Value, value is <func(main.Student) Value>
kind is struct
the name of the type is Value
the full name of the type is reflect.Value
the size of the type is 24
the num of fields is 3 and the mum of method is 60
-- fields:
-- 0: typ *reflect.rtype = &{8 8 3604702347 2 8 8 51 0x5d43c0 0x51f99a 36918 0}
-- 1: ptr unsafe.Pointer = 0x50b090
-- 2: flag reflect.flag = 19
-- methods:
-- 0: name: Addr, func(reflect.Value) reflect.Value
-- 1: name: Bool, func(reflect.Value) bool
-- 2: name: Bytes, func(reflect.Value) []uint8
-- 3: name: Call, func(reflect.Value, []reflect.Value) []reflect.Value
-- 4: name: CallSlice, func(reflect.Value, []reflect.Value) []reflect.Value
-- 5: name: CanAddr, func(reflect.Value) bool
-- 6: name: CanInterface, func(reflect.Value) bool
-- 7: name: CanSet, func(reflect.Value) bool
-- 8: name: Cap, func(reflect.Value) int
-- 9: name: Close, func(reflect.Value)
-- 10: name: Complex, func(reflect.Value) complex128
-- 11: name: Convert, func(reflect.Value, reflect.Type) reflect.Value
-- 12: name: Elem, func(reflect.Value) reflect.Value
-- 13: name: Field, func(reflect.Value, int) reflect.Value
-- 14: name: FieldByIndex, func(reflect.Value, []int) reflect.Value
-- 15: name: FieldByName, func(reflect.Value, string) reflect.Value
-- 16: name: FieldByNameFunc, func(reflect.Value, func(string) bool) reflect.Value
-- 17: name: Float, func(reflect.Value) float64
-- 18: name: Index, func(reflect.Value, int) reflect.Value
-- 19: name: Int, func(reflect.Value) int64
-- 20: name: Interface, func(reflect.Value) interface {}
-- 21: name: InterfaceData, func(reflect.Value) [2]uintptr
-- 22: name: IsNil, func(reflect.Value) bool
-- 23: name: IsValid, func(reflect.Value) bool
-- 24: name: Kind, func(reflect.Value) reflect.Kind
-- 25: name: Len, func(reflect.Value) int
-- 26: name: MapIndex, func(reflect.Value, reflect.Value) reflect.Value
-- 27: name: MapKeys, func(reflect.Value) []reflect.Value
-- 28: name: MapRange, func(reflect.Value) *reflect.MapIter
-- 29: name: Method, func(reflect.Value, int) reflect.Value
-- 30: name: MethodByName, func(reflect.Value, string) reflect.Value
-- 31: name: NumField, func(reflect.Value) int
-- 32: name: NumMethod, func(reflect.Value) int
-- 33: name: OverflowComplex, func(reflect.Value, complex128) bool
-- 34: name: OverflowFloat, func(reflect.Value, float64) bool
-- 35: name: OverflowInt, func(reflect.Value, int64) bool
-- 36: name: OverflowUint, func(reflect.Value, uint64) bool
-- 37: name: Pointer, func(reflect.Value) uintptr
-- 38: name: Recv, func(reflect.Value) (reflect.Value, bool)
-- 39: name: Send, func(reflect.Value, reflect.Value)
-- 40: name: Set, func(reflect.Value, reflect.Value)
-- 41: name: SetBool, func(reflect.Value, bool)
-- 42: name: SetBytes, func(reflect.Value, []uint8)
-- 43: name: SetCap, func(reflect.Value, int)
-- 44: name: SetComplex, func(reflect.Value, complex128)
-- 45: name: SetFloat, func(reflect.Value, float64)
-- 46: name: SetInt, func(reflect.Value, int64)
-- 47: name: SetLen, func(reflect.Value, int)
-- 48: name: SetMapIndex, func(reflect.Value, reflect.Value, reflect.Value)
-- 49: name: SetPointer, func(reflect.Value, unsafe.Pointer)
-- 50: name: SetString, func(reflect.Value, string)
-- 51: name: SetUint, func(reflect.Value, uint64)
-- 52: name: Slice, func(reflect.Value, int, int) reflect.Value
-- 53: name: Slice3, func(reflect.Value, int, int, int) reflect.Value
-- 54: name: String, func(reflect.Value) string
-- 55: name: TryRecv, func(reflect.Value) (reflect.Value, bool)
-- 56: name: TrySend, func(reflect.Value, reflect.Value) bool
-- 57: name: Type, func(reflect.Value) reflect.Type
-- 58: name: Uint, func(reflect.Value) uint64
-- 59: name: UnsafeAddr, func(reflect.Value) uintptr
== 通过反射修改对象=====
value to modify of pointer: 1.2345
settability of pointer: false
settability of newValue: true
type of newValue: float64
new value of pointer: 77
new value of pointer type: float64
value of student2 is {eagle 10}
type of student2 is main.Student
new value of pointer: 77
```
**参考文章:**
[谈谈Go语言的反射三定律](https://www.jb51.net/article/90021.htm)
[一看就懂系列之Golang的反射](https://blog.csdn.net/u011957758/article/details/81193806)
[Golang的反射reflect深入理解和示例](https://studygolang.com/articles/12348?fr=sidebar)
有疑问加站长微信联系(非本文作者))