zoukankan      html  css  js  c++  java
  • golang 反射

    反射机制是指在程序运行的时候动态地获取对象的属性后者调用对象方法的功能。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

  • 相关阅读:
    杭电2063 过山车 匈牙利算法
    杭电2023 平均成绩
    leveldb性能分析
    linux下libreoffice安装测试
    iptables配置vsftp访问
    vsftp访问异常
    mysql二进制安装
    vi命令
    mysql配置优化
    rsync 配置
  • 原文地址:https://www.cnblogs.com/hatlonely/p/11945431.html
Copyright © 2011-2022 走看看