Go 语言反射使用示例

2021/05/28

Categories: 技术 Tags: Golang

反射常用操作示例

判断 Struct 是否实现了指定的 Interface

type I interface {
    Foo()
    Bar()
}

type S struct {}

func (*S) Foo() {
    fmt.Println("foo")
}

func (*S) Bar() {
    fmt.Println("bar")
}

func main() {

    iType := reflect.TypeOf((*I)(nil)).Elem()

    fmt.Println(reflect.TypeOf(S{}).Implements(iType)) // output: false
    fmt.Println(reflect.TypeOf(&S{}).Implements(iType)) // output: true
}

反射调用 Struct 的指定方法

type S struct{}

func (*S) Hello() {
    fmt.Println("hello world")
}

func main() {
    ref := reflect.New(reflect.TypeOf(S{}))
    method := ref.MethodByName("Hello")
    if method.IsValid() {
        method.Call(nil)
    }
}

通过函数签名动态调用函数

// foo sum of nums
func foo(nums ...int) int {
    var sum int
    for _, num := range nums {
        sum += num
    }
    return sum
}

// println string
func bar(s string) {
    fmt.Println(s)
}

func exec(call interface{}, args ...interface{}) ([]reflect.Value, error) {
    f := reflect.ValueOf(call)
    if f.Kind() != reflect.Func {
        return nil, errors.New("call must be func")
    }

    n := len(args)
    params := make([]reflect.Value, n)
    for i := 0; i < n; i++ {
        params[i] = reflect.ValueOf(args[i])
    }
    return f.Call(params), nil
}

func main() {
    // foo(1, 2, 3, 4, 5) return 15
    res, _ := exec(foo, 1, 2, 3, 4, 5)
    fmt.Println(res[0].Int()) // 15

    // bar("hello world")
    _, _ = exec(bar, "hello world")
}

通过 Tag 修改对应字段的默认值

type T struct {
    X int    `default:"10"`
    S string `default:"hello"`
    B bool   `default:"true"`
}

func (t T) String() string {
    return fmt.Sprintf("[ %v, %v, %v ] ", t.X, t.S, t.B)
}

func setDefault(tag string, value reflect.Value, field reflect.StructField) {
    // 获取 tag 内容
    df := field.Tag.Get(tag)

    // 判断是否可改(私有属性无法设置)
    if value.CanSet() {
        // 根据类型修改为不同的值
        switch field.Type.Kind() {
        case reflect.String:
            value.SetString(df)
        case reflect.Int:
            i, err := strconv.Atoi(df)
            if err != nil {
                value.SetInt(0)
            } else {
                value.SetInt(int64(i))
            }
        case reflect.Bool:
            value.SetBool(df == "true")
        case reflect.Float64:
            i, err := strconv.Atoi(df)
            if err != nil {
                value.SetFloat(0)
            } else {
                value.SetFloat(float64(i))
            }
        default:
        }
    }
}

func main() {
    t := T{}
    fmt.Println(t) // output: [ 0, , false ]

    // 反射设置默认值
    tt := reflect.TypeOf(t)
    vt := reflect.ValueOf(&t)
    for i := 0; i < tt.NumField(); i++ {
        field := tt.Field(i)
        value := vt.Elem().Field(i)
        setDefault("default", value, field)
    }

    fmt.Println(t) // output: [ 10, hello, true ]
}

参考文档