1、信息获取
reflect提供了两种类型来进行访问接口变量的内容:
类型 | 作用 |
---|---|
ValueOf | 获取输入参数接口中的数据的值,如果为空则返回0 <- 注意是0 |
TypeOf | 动态获取输入参数接口中的值的类型,如果为空则返回nil <- 注意是nil |
2、示例代码
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Count int
}
func main() {
test(Person{
Name: "lei",
Count: 2,
})
}
func test(body interface{}) {
//TypeOf会返回目标数据的类型,比如int/float/struct/指针等
typ := reflect.TypeOf(body)
//ValueOf返回目标数据的的值
val := reflect.ValueOf(body)
if val.Kind() != reflect.Struct {
fmt.Println("expect struct")
return
}
fmt.Println(typ)
fmt.Println(val)
for i := 0; i < val.NumField(); i++ {
field := typ.Field(i) //字段的数据类型
value := val.Field(i) //字段的数据值
fmt.Println("type1:", field) //type: {Name string json:"name" 0 [0] false}
fmt.Println("value1:", value) //value: lei
switch value.Kind() {
case reflect.Int:
value.SetInt(88) //往该字段设值
case reflect.String:
//这里存在一个问题无法对字段进行值修改,panic:reflect: reflect.flag.mustBeAssignable using unaddressable value,后文介绍解决
value.SetString("Test") // 往该字段设值
default:
fmt.Println("类型不支持")
}
fmt.Println("type2:", field) //type: {Name string json:"name" 0 [0] false}
fmt.Println("value2:", value) //value: Test
tag := field.Tag
fmt.Println(tag.Get("json"))
}
}
3、函数说明
3.1、val.Kind()
// Kind returns v's Kind.
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
func (v Value) Kind() Kind {
return v.kind()
}
返回值为Kind,表示golang语言自身定义的基本类型:
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
3.2、val.NumField()
// NumField returns the number of fields in the struct v.
// It panics if v's Kind is not Struct.
func (v Value) NumField() int {
v.mustBe(Struct)
tt := (*structType)(unsafe.Pointer(v.typ))
return len(tt.fields)
}
v.mustBe(Struct)
3.3、typ.Field(i)
// Field returns a struct type's i'th field.
// It panics if the type's Kind is not Struct.
// It panics if i is not in the range [0, NumField()).
type Type interface {
Field(i int) StructField
}
i
// A StructField describes a single field in a struct.
type 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
}
field.TagStructTag
// 只是复用了Lookup,只不过忽略了标签存在的说明,不存在返回“”
func (tag StructTag) Get(key string) string {
v, _ := tag.Lookup(key)
return v
}
// 返回标签对应的值与标签是否存在的说明
func (tag StructTag) Lookup(key string) (value string, ok bool) {
// When modifying this code, also update the validateStructTag code
// in cmd/vet/structtag.go.
...
}
_3.4、_value.SetString(“Test”)
value.SetString("Test")panic: reflect: reflect.flag.mustBeAssignable using unaddressable value&Person
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Count int
}
func (p *Person) Print() {
fmt.Println("print:",p)
}
func (p *Person) CountAdd(num int) int {
return p.Count + num
}
func main() {
test(&Person{
Name: "lei",
Count: 2,
})
}
func test(body interface{}) {
//TypeOf会返回目标数据的类型,比如int/float/struct/指针等
typ := reflect.TypeOf(body)
//ValueOf返回目标数据的的值
val := reflect.ValueOf(body)
if val.Elem().Kind() != reflect.Struct {
fmt.Println("expect struct")
return
}
fmt.Println(typ)
fmt.Println(val)
for i := 0; i < val.Elem().NumField(); i++ {
field := typ.Elem().Field(i) //字段的数据类型
value := val.Elem().Field(i) //字段的数据值
fmt.Println("type1:", field) //type: {Name string json:"name" 0 [0] false}
fmt.Println("value1:", value) //value: lei
switch value.Kind() {
case reflect.Int:
value.SetInt(88) //往该字段设值
case reflect.String:
value.SetString("Test") // 往该字段设值
default:
fmt.Println("类型不支持")
}
fmt.Println("type2:", field) //type: {Name string json:"name" 0 [0] false}
fmt.Println("value2:", value) //value: Test
fmt.Println(field.Tag.Get("json"))
}
}
4、方法调用
4.1、val调用
call := val.Method(0).Call([]reflect.Value{reflect.ValueOf(2)}) //调用CountAdd方法
fmt.Println("返回值:", call[0]) //返回值: 90
val.MethodByName("Print").Call(nil) //通过方法名调用
func (v Value) Call(in []Value) []Value
4.2、typ查看方法信息
for i := 0; i < typ.NumMethod(); i++ {
method := typ.Method(i)
fmt.Println(method.Name,method.Type) //CountAdd func(*main.Person, int) int
}
typ.Method(i)
// Method represents a single 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
}
4.3、typ方法调用
for i := 0; i < typ.NumMethod(); i++ {
method := typ.Method(i)
fmt.Println(method.Name,method.Type) //CountAdd func(*main.Person, int) int
if method.Name == "CountAdd" {
//对于Type类型包含的方法,因为没有实际值作为接收者,需要吧传入的第一个参数作为接收者
retInfo := method.Func.Call([]reflect.Value{val,reflect.ValueOf(2)})
fmt.Println("返回值:", retInfo[0])
}
}
method, ok := typ.MethodByName("Print")
if ok {
method.Func.Call([]reflect.Value{val})
}
5、完整示例代码
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Count int
}
func (p *Person) Print() {
fmt.Println("print:", p) //print: &{Test 88}
}
func (p *Person) CountAdd(num int) int {
return p.Count + num
}
func main() {
test(&Person{
Name: "lei",
Count: 2,
})
}
func test(body interface{}) {
//TypeOf会返回目标数据的类型,比如int/float/struct/指针等
typ := reflect.TypeOf(body)
//ValueOf返回目标数据的的值
val := reflect.ValueOf(body)
if val.Elem().Kind() != reflect.Struct {
fmt.Println("expect struct")
return
}
fmt.Println(typ)
fmt.Println(val)
for i := 0; i < val.Elem().NumField(); i++ {
field := typ.Elem().Field(i) //字段的数据类型
value := val.Elem().Field(i) //字段的数据值
fmt.Println("type1:", field) //type: {Name string json:"name" 0 [0] false}
fmt.Println("value1:", value) //value: lei
switch value.Kind() {
case reflect.Int:
value.SetInt(88) //往该字段设值
case reflect.String:
value.SetString("Test") // 往该字段设值
default:
fmt.Println("类型不支持")
}
fmt.Println("type2:", field) //type: {Name string json:"name" 0 [0] false}
fmt.Println("value2:", value) //value: Test
fmt.Println(field.Tag.Get("json"))
}
// 除解析一个接口的结构字段和方法外,还可以对注册在结构上的方法进行调用
// 调用过程中需要注意接收者是否为指针型,被调用函数应当是被导出类型
// 这个调用过程只能在包含了结构实例值的Value类型上使用,Type类型无法使用
// func (v Value) Call(in []Value) []Value
// 参数和返回值都是reflect包中Value型的切片,需要经过转换
call := val.Method(0).Call([]reflect.Value{reflect.ValueOf(2)}) //调用CountAdd方法
fmt.Println("返回值:", call[0]) //返回值: 90
val.MethodByName("Print").Call(nil) //通过方法名调用
for i := 0; i < typ.NumMethod(); i++ {
method := typ.Method(i)
fmt.Println(method.Name,method.Type) //CountAdd func(*main.Person, int) int
if method.Name == "CountAdd" {
//对于Type类型包含的方法,因为没有实际值作为接收者,需要吧传入的第一个参数作为接收者
retInfo := method.Func.Call([]reflect.Value{val,reflect.ValueOf(2)})
fmt.Println("返回值:", retInfo[0])
}
}
method, ok := typ.MethodByName("Print")
if ok {
method.Func.Call([]reflect.Value{val})
}
}