• golang reflect


    golang reflect

    go语言中reflect反射机制。详细原文:地址

    接口值到反射对象

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        var x int = 1
        fmt.Println("type: ", reflect.TypeOf(x))
    }
    
    
    type:  int
    

    TypeOf函数的定义如下,参数为接口类型,返回值为类型

    func TypeOf(i interface {}) Type
    

    ValueOf函数的定义如下,参数为接口类型,返回值为Value

    var x int = 1
    fmt.Println("value: ", reflect.ValueOf(x))
    
    value:  <int Value>
    

    可以通过Kind函数来检查类型,

    fmt.Println("Kind:  ", reflect.ValueOf(x).Kind())
    fmt.Println("Kind is Int? ", reflect.ValueOf(x).Kind() == reflect.int)
    
    Kind:   int
    Kind is Int?  true
    

    反射对象到接口值

    通过Interface函数可以实现反射对象到接口值的转换,

    func (v Value) Interface() interface {}
    
    // Interface 以 interface{} 返回 v 的值
    y := v.Interface().(float64)
    fmt.Println(y)
    

    修改反射对象

    修改反射对象的前提条件是其值必须是可设置的

    var x float64 = 3.4
    v := reflect.ValueOf(x)
    v.SetFloat(7.3) // Error: panic
    

    为了避免这个问题,需要使用CanSet函数来检查该值的设置性,

    var x float64 = 3.4
    v := reflect.ValueOf(x)
    fmt.Println("settability of v: ", v.CanSet())
    
    settability of v: false
    

    那么如何才能设置该值呢?
    这里需要考虑一个常见的问题,参数传递,传值还是传引用或地址?
    在上面的例子中,我们使用的是reflect.ValueOf(x),这是一个值传递,传递的是x的值的一个副本,不是x本身,因此更新副本中的值是不允许的。如果使用 reflect.ValueOf(&x)来替换刚才的值传递,就可以实现值的修改。

    
    var x float64 = 3.4
    p := reflect.ValueOf(&x) // 获取x的地址
    fmt.Println("settability of p: ", p.CanSet())
    v := p.Elem()
    fmt.Println("settability of v: ", v.CanSet())
    v.SetFloat(7.1)
    fmt.Println(v.Interface())
    fmt.Println(x)
    
    settability of p: false
    settability of v: true
    7.1
    7.1
    
    

    获取结构体标签

    首先介绍如何遍历结构体字段内容,
    假设结构体如下,

    type T struct {
        A int
        B string
    }
    
    t := T{12, "skidoo"}
    

    从而,通过反射来遍历所有的字段内容

    s := reflect.ValueOf(&t).Elem()
    typeOfT := s.Type()
    for i := 0; i < s.NumField(); i++ {
        f := s.Field(i)
        fmt.Printf("%d %s %s = %v
    ", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
    }
    
    0 A int = 23
    1 B string = skidoo
    

    接下来,如何获取结构体的标签内容?

    func main() {
        type S struct {
            F string `species:"gopher" color:"blue"`
        }
    
        s := S{}
        st := reflect.TypeOf(s)
        field := st.Field(0)
        fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"))
    }
    

    interface{}到函数反射

    一般情况下,为了存储多个函数值,一般采用map来存储。其中key为函数名称,而value为相应的处理函数。
    在这里需要定义好函数类型,但是函数的参数以及返回类型就需要是统一的,如下

    package main
    
    import "fmt"
    
    func say(text string) {
        fmt.Println(text)
    }
    
    func main() {
        var funcMap = make(map[string]func(string))
        funcMap["say"] = say
        funcMap["say"]("hello")
    }
    

    如果希望map可以存储任意类型的函数(参数不同,返回值不同),那么就需要用interface{}而不是func(param...)来定义value。

    package main
    
    import "fmt"
    
    func say(text string) {
        fmt.Println(text)
    }
    
    func main() {
        var funcMap = make(map[string]interface{})
        funcMap["say"] = say
        funcMap["say"]("hello")
    }
    
    cannot call non-function funcMap["say"] (type interface {})
    

    直接调用会报错,提示不能调用interface{}类型的函数。

    这时,需要利用reflect把函数从interface转换到函数来使用,

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func say(text string) {
        fmt.Println(text)
    }
    
    func Call(m map[string]interface{}, name string, params ... interface{}) (result []reflect.Value) {
        f := reflect.ValueOf(m[name])
        in := make([]reflect.Value, len(params))
        for k, param := range params {
            in[k] = reflect.ValueOf(param)
        }
        result = f.Call(in)
        return
    }
    
    func main() {
        var funcMap = make(map[string]interface{})
        funcMap["say"] = say
        Call(funcMap, "say", "hello")
    
  • 相关阅读:
    面试常考点:http和https的区别与联系
    常见的反爬虫和应对方法
    2019/1/1 Python今日收获
    2018/12/26,12/27 Python今日收获
    2018/6/7-6/8 Python今日收获
    2018/6/6 Python今日收获
    CSS(3)——visited伪类
    CSS中margin和padding的区别
    CSS(2)——CSS的文字,边框,背景与列表
    CSS(1)——CSS的引入方式与选择器
  • 原文地址:https://www.cnblogs.com/coder2012/p/4881854.html
Copyright © 2020-2023  润新知