golang 反射

· · 529 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

反射机制是指在程序运行的时候动态地获取对象的属性后者调用对象方法的功能。golang 支持反射,原生的 json 库就是用反射机制实现。

golang 的反射有两个主要的概念: reflect.Typereflect.Value 从字面上理解就是类型和值

reflect.Type

reflect.Type 指的就是一个类型,可以是基本类型 int,string,也可以是自定义的结构体类型,可以通过 reflect.TypeOf() 获取对象的类型

TypeOf(i interface{}) Type  // 获取任意一个对象的 Type 对象

(t *Type) NumField() int    // 字段数量
(t *Type) NumMethod() int   // 方法数量
(t *Type) Field(i int) StructField  // 返回第 i 个字段
(t *Type) FieldByName(name string) (StructField, bool)  // 根据字段名获取字段
(t *Type) Name()            // 字段名
(t *Type) Kind() Kind       // 字段类型

type StructField struct {
    Name    string      // 字段名
    PkgPath string      // 包路径
    Type    Type        // 字段类型
    Tag     StructTag   // 字段的 tag
}

(tag StructTag) Get(key string) string  // 获取字段的 tag 中的某个 key

reflect.Value

reflect.Value 指的是一个值,主要的 api

ValueOf(i interface{}) Type  // 获取任意一个对象的 Value 对象

(v Value) NumField() int    // 字段数量
(v Value) NumMethod() int   // 方法数量
(v Value) Field(i int) Value        // 返回第 i 个字段
(v Value) Method(int) Value         // 返回第 i 个方法
(v Value) FieldByName(name string) Value    // 根据字段名获取字段
(v Value) MethodByName(string) Value        // 根据方法名获取字段
(v Value) Type() Type       // 获取的类型

(v Value) Int() int         // 返回 int
(v Value) String() string   // 返回 string
(v Value) Interface() interface{}   // 返回一个 interface,之后可以转成任意对象

(v Value) Call(in []Value) []Value      // 方法调用,参数和返回值都是数组的形式
(v Value) CallSlice(in []Value) []Value // 可变长参数函数调用

举例

type A struct {
    F1 int    `json:"f1"`
    F2 string `json:"f2"`
}

获取类型

t := reflect.TypeOf(A{})
So(t.NumField(), ShouldEqual, 2)
So(t.Field(0).Name, ShouldEqual, "F1")
So(t.Field(0).Type.Kind(), ShouldEqual, reflect.Int)
So(t.Field(0).Tag, ShouldEqual, `json:"f1"`)
So(t.Field(1).Name, ShouldEqual, "F2")
So(t.Field(1).Type.Kind(), ShouldEqual, reflect.String)
So(t.Field(1).Tag, ShouldEqual, `json:"f2"`)

获取 tag

So(reflect.TypeOf(A{}).Field(0).Tag.Get("json"), ShouldEqual, "f1")
So(reflect.TypeOf(A{}).Field(1).Tag.Get("json"), ShouldEqual, "f2")

获取值

a := A{
    F1: 10,
    F2: "hatlonely",
}
v := reflect.ValueOf(a)
So(v.NumField(), ShouldEqual, 2)
So(v.Field(0).Int(), ShouldEqual, 10)
So(v.Field(1).String(), ShouldEqual, "hatlonely")
So(v.Field(0).Type().Kind(), ShouldEqual, reflect.Int)
So(v.Field(1).Type().Kind(), ShouldEqual, reflect.String)
So(v.FieldByName("F1").Int(), ShouldEqual, 10)
So(v.FieldByName("F2").Interface().(string), ShouldEqual, "hatlonely")

调用方法,这里要注意,方法的 receiver 是指针还是对象,value 的类型应该和 receiver 保持一致

func (a *A) Add(b int) int {
    a.F1 += b
    return a.F1
}

func (a A) Mul(b int) int {
    return a.F1 * b
}

func (a A) Sum(vi ...int) int {
    sum := 0
    for _, i := range vi {
        sum += i
    }

    return sum + a.F1
}

a := A{
    F1: 10,
}

So(reflect.ValueOf(a).MethodByName("Mul").Call([]reflect.Value{reflect.ValueOf(20)})[0].Int(), ShouldEqual, 200)
So(a.F1, ShouldEqual, 10)
So(reflect.ValueOf(&a).MethodByName("Add").Call([]reflect.Value{reflect.ValueOf(20)})[0].Int(), ShouldEqual, 30)
So(a.F1, ShouldEqual, 30)
So(reflect.ValueOf(a).MethodByName("Sum").Call([]reflect.Value{
    reflect.ValueOf(30), reflect.ValueOf(40), reflect.ValueOf(50),
})[0].Int(), ShouldEqual, 150)
So(reflect.ValueOf(a).MethodByName("Sum").CallSlice([]reflect.Value{
    reflect.ValueOf([]int{30, 40, 50}),
})[0].Int(), ShouldEqual, 150)

链接

转载请注明出处
本文链接:https://tech.hatlonely.com/article/59


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:

查看原文:golang 反射

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

529 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传