package main
import("fmt""reflect")funcmain(){
a :=10
t := reflect.TypeOf(a)
fmt.Printf("%T, %[1]v\n", t)// *reflect.rtype, int
fmt.Printf("%T, %[1]v\n", t.String())// string, int}
package main
import("fmt""reflect")// Person 测试结构体type Person struct{
Name string`json:"name"`
Age int`json:"age"`}// Stu 测试结构体type Stu struct{
Score int// 这种就是匿名引用, 如果是 Person Person, 就不是匿名引用, 第一个 Person 为命名, 第二个为指定的结构体类型
Person
}funcmain(){// 实例化
stu1 := Stu{
Score:100,
Person: Person{
Name:"Tim",
Age:30,},}// 拿到 Type
t := reflect.TypeOf(stu1)// 取属性, 方式1, 根据索引
sf1 := t.Field(1)// {Person main.Person 8 [1] true}, 这个 true 说明 stu 结构体中的 person 结构体是匿名引用
fmt.Println(sf1)// 取属性, 方式2, 根据 key
sf2, ok := t.FieldByName("Person")if ok {
fmt.Println(sf2)}// 根据索引取嵌套的属性
sf3 := t.FieldByIndex([]int{1,1})
fmt.Println(sf3)// 上边三个返回值是 StructField 结构体, {Age int json:"age" 16 [1] false}, 以这个举例
fmt.Println(sf3.Name)// Age, 结构体属性名
fmt.Println(sf3.Type)// int, 结构体属性数据类型
fmt.Println(sf3.Tag)// json:"age", 结构体属性 json tag
fmt.Println(sf3.Index)// [1], 属性在当前结构体的索引}
方法相关 - NumMethod(), Method(), MethodByName()
NumMethod() 这个方法只统计暴露给外部,并且是值接收者的方法
package main
import("fmt""reflect")type stu struct{
name string
age int
score int}func(s stu)Study()string{return"study"}func(s *stu)ChangeScore(newScore int){
s.score = newScore
}funcmain(){
stu1 := stu{
name:"Tim",
age:18,
score:100,}
t := reflect.TypeOf(stu1)// 获取方法数量, 这个方法只统计暴露给外部,并且是值接收者的方法
numMethod := t.NumMethod()for i :=0; i < numMethod; i++{// 根据索引
fmt.Println(t.Method(i).Name)}// 根据字符串取方法
m, ok := t.MethodByName("Study")if ok {
fmt.Println(m.Name)}}
源码
TypeOf 实现
funcTypeOf(i interface{}) Type {
eface :=*(*emptyInterface)(unsafe.Pointer(&i))returntoType(eface.typ)}
Type接口
type Type interface{String()string// 直接打印就是这个Kind() Kind // 返回种类Name()string// 返回类型Elem() Type // 获取指针对应的值NumField()int// 获取属性数量Field(i int) StructField // 根据索引获取属性FieldByIndex(index []int) StructField // 根据索引获取多个属性FieldByName(name string)(StructField,bool)// 根据字符串获取属性NumMethod()int// 获取方法数量Method(int) Method // 根据索引获取方法MethodByName(string)(Method,bool)// 根据字符串获取方法FieldByNameFunc(match func(string)bool)(StructField,bool)Align()intFieldAlign()intPkgPath()stringSize()uintptrImplements(u Type)boolAssignableTo(u Type)boolConvertibleTo(u Type)boolComparable()boolBits()intChanDir() ChanDir
IsVariadic()boolIn(i int) Type
Key() Type
Len()intNumIn()intNumOut()intOut(i int) Type
common()*rtype
uncommon()*uncommonType
}
// Field, FieldByIndex, FieldByName 返回值都是StructFieldtype StructField struct{// Name is the field name.
Name string// PkgPath is the package path that qualifies a lower case (unexported)// field name. It is empty for upper case (exported) field names.// See https://golang.org/ref/spec#Uniqueness_of_identifiers
PkgPath string
Type Type // field type
Tag StructTag // field tag string
Offset uintptr// offset within struct, in bytes
Index []int// index sequence for Type.FieldByIndex
Anonymous bool// is an embedded field}
Method结构体源码
type Method struct{// Name is the method name.// PkgPath is the package path that qualifies a lower case (unexported)// method name. It is empty for upper case (exported) method names.// The combination of PkgPath and Name uniquely identifies a method// in a method set.// See https://golang.org/ref/spec#Uniqueness_of_identifiers
Name string
PkgPath string
Type Type // method type
Func Value // func with receiver as first argument
Index int// index for Type.Method}
ValueOf
根据变量名获取值
package main
import("fmt""reflect")funcmain(){
a :=10// 拿到 Value
v := reflect.ValueOf(a)// 这里输出的就是值
fmt.Println(v)}
方法
类型相关 - Kind()
Value 可以调用 Type(), 得到一个 Type
Value 和 Type 都可以使用 Kind() 方法, 用法相同
package main
import("fmt""reflect")funcmain(){var a int8
a =18// ValueOf(a) --> Value.Kind() --> Type
v := reflect.ValueOf(a).Kind()
fmt.Println(v.String())// int8}
修改值 - Elem()
package main
import("fmt""reflect")funcmain(){
a :=10// 拿到 Value
e := reflect.ValueOf(&a).Elem()
k := e.Kind()// 对应类型, 选择相应的修改方法进行修改switch k {case reflect.Int:
e.SetInt(100)default:
fmt.Println("not string")}// 验证结果, 100
fmt.Println(a)}