zoukankan      html  css  js  c++  java
  • 【原创】go语言学习(十八)反射详解

    目录

    • 变量介绍
    • 反射介绍
    • 结构体反射
    • 反射总结以及应用场景

    变量介绍

    1、变量的内在机制

    A. 类型信息,这部分是元信息,是预先定义好的
    B. 值类型,这部分是程序运行过程中,动态改变的

    var arr [10]int
    arr[0] = 10
    arr[1] = 20
    arr[2] = 30
    arr[3] = 40
    arr[4] = 50
    
    type Animal struct {
        Name string
        age int
    }
    var a Animal
    

      

    反射介绍

    1、 反射与空接口

    A. 空接口可以存储任何类型的变量

    B. 那么给你一个空接口,怎么里面存储的是什么东西?

    C. 在运行时动态的获取一个变量的类型信息和值信息,就叫反射

    2、怎么分析?

    A. 内置包 reflect
    B. 获取类型信息: reflect.TypeOf
    C. 获取值信息: reflect.ValueOf

    3、 基本数据类型分析?

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

      

    4、 Type.Kind(),获取变量的类型

    package main
    import (
        "fmt"
        "reflect"
    )
    func main() {
        var x float64 = 3.4
        t := reflect.TypeOf(x)
        fmt.Println("type:", t.Kind())
    }
    

      

    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
    )
    

      

    5、 reflect.ValueOf,获取变量的值相关信息

    var x float64 = 3.4
    v := reflect.ValueOf(x)
    //和reflect.TypeOf功能是一样的
    fmt.Println("type:", v.Type())
    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
    fmt.Println("value:", v.Float())
    

      

    6、 通过反射设置变量的值

    var x float64 = 3.4
    v := reflect.ValueOf(x)
    fmt.Println("type:", v.Type())
    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
    v.SetFloat(6.8)
    fmt.Println("value:", v.Float())
    

      

    7、通过反射设置变量的值

    var x float64 = 3.4
    //传地址进去,不传地址的话,改变的是副本的值
    //所以在reflect包里直接崩溃了!!!!!
    v := reflect.ValueOf(&x)
    fmt.Println("type:", v.Type())
    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
    v.SetFloat(6.8)
    fmt.Println("value:", v.Float())
    

      

    8、通过反射设置变量的值

    var x float64 = 3.4
    //传地址进去,不传地址的话,改变的是副本的值
    //所以在reflect包里直接崩溃了!!!!!
    v := reflect.ValueOf(&x)
    fmt.Println("type:", v.Type())
    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
    //通过Elem()获取指针指向的变量,从而完成赋值操作。
    //正常操作是通过*号来解决的,比如
    //var *p int = new(int)
    //*p = 100
    v.Elem().SetFloat(6.8)
    fmt.Println("value:", v.Float())
    

      

    9、通过反射设置变量的值

    var x float64 = 3.4
    v := reflect.ValueOf(&x)
    fmt.Println("type:", v.Type())
    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
    v.Elem().SetInt(100)
    fmt.Println("value:", v.Float())
    

      

    结构体反射

    1、获取结构体类型相关信息

    package main
    import (
        "fmt"
        "reflect"
    )
    type S struct {
        A int
        B string
    }
    func main() {
        s := S{23, "skidoo"}
        v := reflect.ValueOf(s)
        t := v.Type()
        for i := 0; i < v.NumField(); i++ {
            f := v.Field(i)
            fmt.Printf("%d: %s %s = %v
    ", i,
            t.Field(i).Name, f.Type(), f.Interface())
        }
    }
    

      

    2、 获取结构体类型相关信息

    package main
    import (
        "fmt"
        "reflect"
    )
    type S struct {
        A int
        B string
    }
    func main() {
        s := S{23, "skidoo"}
        v := reflect.ValueOf(s)
        t := v.Type()
        for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        fmt.Printf("%d: %s %s = %v
    ", i,
            t.Field(i).Name, f.Type(), f.Interface())
        }
    }
    

      

    3、设置结构体相关字段的值

    package main
    import (
        "fmt"
        "reflect"
    )
    type S struct {
        A int
        B string
    }
    func main() {
        s := S{23, "skidoo"}
        v := reflect.ValueOf(&s)
        t := v.Type()
        v.Elem().Field(0).SetInt(100)
        for i := 0; i < v.Elem().NumField(); i++ {
            f := v.Elem().Field(i)
            fmt.Printf("%d: %s %s = %v
    ", i,
            t.Elem().Field(i).Name, f.Type(), f.Interface())
        }
    }
    

      

    4、 获取结构体的方法信息

    package main
    import (
        "fmt"
        "reflect"
    )
    type S struct {
        A int
        B string
    }
    func (s *S) Test() {
        fmt.Println("this is a test")
    }
    func main() {
        s := S{23, "skidoo"}
        v := reflect.ValueOf(&s)
        t := v.Type()
        v.Elem().Field(0).SetInt(100)
        fmt.Println("method num:", v.NumMethod())
        for i := 0; i < v.NumMethod(); i++ {
            f := t.Method(i)
            fmt.Printf("%d method, name:%v, type:%v
    ", i, f.Name, f.Type)
        }
    }
    

      

    5、调用结构体中的方法

    package main
    import (
        "fmt"
        "reflect"
    )
    type S struct {
        A int
        B string
    }
    func (s *S) Test() {
        fmt.Println("this is a test")
    }
    func (s *S)SetA(a int) {
        s.A = a
    }
    func main() {
        s := S{23, "skidoo"}
        v := reflect.ValueOf(&s)
        m := v.MethodByName("Test")
        var args1 []reflect.Value
        m.Call(args1)
        setA := v.MethodByName("SetA")
        var args2 []reflect.Value
        args2 = append(args2, reflect.ValueOf(100))
        setA.Call(args2)
        fmt.Printf("s:%#v
    ", s)
    }
    

      

    6、获取结构体中tag信息

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

     

    反射总结以及应用场景

    1、反射总结

    A.在运行时动态的获取一个变量的类型信息和值信息

    2. 应用场景

    A. 序列化和反序列化,比如json, protobuf等各种数据协议
    B. 各种数据库的ORM, 比如gorm,sqlx等数据库中间件
    C. 配置文件解析相关的库, 比如yaml、ini等

  • 相关阅读:
    WindowsServer 2016激活
    selenium浏览器复用与原理分析
    react脚手架: 配置代理
    网络请求方式
    Java: Excel导入导出
    react 组件通信方式
    react: reactrouterdom
    react: 高阶函数及函数柯里化
    react: 事件处理
    react: 生命周期
  • 原文地址:https://www.cnblogs.com/wangshuyang/p/11815758.html
Copyright © 2011-2022 走看看