您诸位好啊,我是无尘!
对于反射,之前的文章已经有所介绍,传送门:《断言、反射的理解与使用!》,此处我们再深入讲解下反射。
反射有两种类型 reflect.Value
和 reflect.Type
,分别表示变量的值和类型,并且提供了两个函数 reflect.ValueOf
和 reflect.TypeOf
分别获取任意对象的 reflect.Value
和 reflect.Type
。
reflect.Value
可以通过函数 reflect.ValueOf
获得。reflect.Value
被定义为一个 struct 结构体:
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
可以看到,这个结构体中的字段都是私有的,我们只能使用 reflect.Value 的方法,它的方法有:
//针对具体类型的系列方法
//以下是用于获取对应的值
Bool
Bytes
Complex
Float
Int
String
Uint
CanSet //是否可以修改对应的值
//以下是用于修改对应的值
Set
SetBool
SetBytes
SetComplex
SetFloat
SetInt
SetString
Elem //获取指针指向的值,一般用于修改对应的值
//以下Field系列方法用于获取struct类型中的字段
Field
FieldByIndex
FieldByName
FieldByNameFunc
Interface //获取对应的原始类型
IsNil //值是否为nil
IsZero //值是否是零值
Kind //获取对应的类型类别,比如Array、Slice、Map等
//获取对应的方法
Method
MethodByName
NumField //获取struct类型中字段的数量
NumMethod//类型上方法集的数量
Type//获取对应的reflect.Type
方法分为三类:
func main() {
i := 5
//int to reflect.Value
iv:=reflect.ValueOf(i)
//reflect.Value to int
i1 := iv.Interface().(int)
fmt.Println(i1)
}
func main() {
i := 5
ipv := reflect.ValueOf(&i)
ipv.Elem().SetInt(6)
fmt.Println(i)
}
func main() {
p := person{Name: "微客鸟窝",Age: 18}
pv:=reflect.ValueOf(&p)
pv.Elem().Field(0).SetString("无尘")
fmt.Println(p)
}
type person struct {
Name string
Age int
}
步骤总结:
❝通过反射修改一个值的规则:
❞
因为我们可以通过 type 关键字来自定义一些新的类型,而底层类型就是一些基础类型。比如上面示例中的 p 变量类型为 person,底层类型为 struct 结构体类型。
func main() {
p := person{Name: "微客鸟窝",Age: 18}
pv:=reflect.ValueOf(&p)
fmt.Println(pv.Kind())
pv:=reflect.ValueOf(p)
fmt.Println(pv.Kind())
}
//运行结果:
ptr
struct
Kind 方法返回一个 Kind 类型的值,它是一个常量,从源码看下定义的 Kind 常量列表,含了 Go 语言的所有底层类型:
type Kind uint
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
)
type Type interface {
Implements(u Type) bool //方法用于判断是否实现了接口 u;
AssignableTo(u Type) bool //方法用于判断是否可以赋值给类型 u,其实就是是否可以使用 =,即赋值运算符;
ConvertibleTo(u Type) bool //方法用于判断是否可以转换成类型 u,其实就是是否可以进行类型转换;
Comparable() bool //方法用于判断该类型是否是可比较的,其实就是是否可以使用关系运算符进行比较。
//以下这些方法和Value结构体的功能相同
Kind() Kind
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
NumField() int
}
package main
import (
"fmt"
"reflect"
)
func main() {
p := person{Name: "微客鸟窝", Age: 18}
pt := reflect.TypeOf(p)
//遍历person的字段
for i := 0; i < pt.NumField(); i++ {
fmt.Println("字段:", pt.Field(i).Name)
}
//遍历person的方法
for i := 0; i < pt.NumMethod(); i++ {
fmt.Println("方法:", pt.Method(i).Name)
}
}
type person struct {
Name string
Age int
}
func (p person) String() string{
return fmt.Sprintf("Name is %s,Age is %d",p.Name,p.Age)
}
运行结果:
字段:Name
字段:Age
方法:String
//....
func main() {
p := person{Name: "微客鸟窝", Age: 20}
pt := reflect.TypeOf(p)
stringerType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()
fmt.Println("是否实现了fmt.Stringer:", pt.Implements(stringerType))
fmt.Println("是否实现了io.Writer:", pt.Implements(writerType))
}
//...
运行结果:
是否实现了fmt.Stringer: true
是否实现了io.Writer: false
我们可以通过标准库中的 json 包进行JSON 和 Struct 互转:
//......
func main() {
p := person{Name: "微客鸟窝", Age: 18}
//struct to json
jsonB, err := json.Marshal(p)
if err == nil {
fmt.Println(string(jsonB))
}
//json to struct
respJSON := "{\"Name\":\"无尘\",\"Age\":18}"
json.Unmarshal([]byte(respJSON), &p)
fmt.Println(p)
}
//......
运行结果:
{"Name":"微客鸟窝","Age":18}
Name is 无尘,Age is 18
struct tag 是一个添加在 struct 字段上的标记,使用它进行辅助。要想获得字段上的 tag,就要先反射获得对应的字段,可以通过 Field 方法做到。该方法返回一个 StructField 结构体,它有一个字段是 Tag,存有字段的所有 tag。 示例:
//遍历person字段中key为json、bson的tag
for i:=0;i<pt.NumField();i++{
sf:=pt.Field(i)
fmt.Printf("字段%s上,json tag为%s\n",sf.Name,sf.Tag.Get("json"))
fmt.Printf("字段%s上,bson tag为%s\n",sf.Name,sf.Tag.Get("bson"))
}
type person struct {
Name string `json:"name" bson:"b_name"`
Age int `json:"age" bson:"b_name"`
}
运行结果:
字段Name上,key为json的tag为name
字段Name上,key为bson的tag为b_name
字段Age上,key为json的tag为age
字段Age上,key为bson的tag为b_name
Go 语言的作者在博客上总结了反射的三大定律:
❝
❞