Golang 反射

Posted zhichaoma

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang 反射相关的知识,希望对你有一定的参考价值。

反射是指程序运行期间对程序本身进行访问和修改的能力

变量的内在机制

  • 变量包含类型信息和值信息
  • 类型信息:是静态的元信息,是预先定义好的
  • 值信息:是程序运行过程中动态改变的

反射的使用

  • reflect 包封装了反射相关的方法
  • 获取类型信息:reflect.TypeOf,是静态的
  • 获取值信息:reflect.ValueOf,是动态的

空接口与反射

  • 反射可以在运行时动态获取程序的各种详细信息
  • 反射获取 interface 类型信息
package main

import (
    "fmt"
    "reflect"
)

// 反射获取interface类型
func relect_type(i interface{}) {
    // typeOf不能直接比较
    t := reflect.TypeOf(i)
    fmt.Println("类型是: ", t)

    // kind() 可以获取具体类型
    k := t.Kind()
    fmt.Println(k)

    switch k {
    case reflect.Float64:
        fmt.Println("i is float64")
    case reflect.String:
        fmt.Println("i is string")
    }
}

func main() {
    var x float64 = 2.4
    relect_type(x)
}

反射获取 interface 值信息

package main

import (
    "fmt"
    "reflect"
)

// 反射获取interface值信息
func relect_value(i interface{}) {
    v := reflect.ValueOf(i)
    fmt.Println(v)
    k := v.Kind()
    switch k {
    case reflect.Float64:
        fmt.Println("a is: ", v.Float())
    }
}

func main() {
    var x float64 = 3.14
    relect_value(x)
}

反射修改值信息

package main

import (
    "fmt"
    "reflect"
)

// 反射修改值信息
func reflect_set_value(i interface{}) {
    v := reflect.ValueOf(i)
    k := v.Kind()
    switch k {
    case reflect.Float64:
        // 值传递无法在反射中修改
        // 反射修改值
        v.SetFloat(99.81)
        fmt.Println("value is, ", v.Float())
    case reflect.Ptr:
        // Elem()获取地址中的值
        v.Elem().SetFloat(88.91)
        fmt.Println("ptr value is, ", v.Elem().Float())
        // 地址
        fmt.Println(v.Pointer())
    }
}

func main() {
    var x float64 = 3.14
    // 反射值类型, 值传递无法在反射中修改
    //reflect_set_value(x)
    //fmt.Println("main value, ", x)
    // 反射一个指针类型
    reflect_set_value(&x)
    fmt.Println("ptr main value, ", x)
}

结构体反射

查看类型、字段和方法

package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

// 绑定方法
func (u User) Hello() {
    fmt.Println("hello")
}

func reflect_struct(i interface{}) {
    t := reflect.TypeOf(i)
    fmt.Println("类型: ", t)
    fmt.Println("字符串类型: ", t.Name())

    // 获取值
    v := reflect.ValueOf(i)
    fmt.Println("值: ", v)
    // 获取结构体所有属性
    // 获取结构体字段个数: t.NumField()
    for i := 0; i < t.NumField(); i++ {
        // 取每个字段
        // 通过interface{} 的 TypeOf()获取
        f := t.Field(i)
        // f.Name 字段名称  f.Type  字段类型
        fmt.Printf("%s : %v	", f.Name, f.Type)

        // 获取字段值信息
        // 通过interface{} 的 ValueOf()获取
        // interface() 获取字段对应的值
        val := v.Field(i).Interface()
        fmt.Println("val: ", val)
    }

    // 获取方法
    // NumMethod(), 获取方法个数
    for i := 0; i < t.NumMethod(); i++ {
        m := t.Method(i)
        fmt.Println("方法名称: ", m.Name)
        fmt.Println("方法类型: ", m.Type)
    }
}

func main() {
    u := User{1, "zs", 20}
    reflect_struct(u)
}

查看匿名字段

package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

type Boy struct {
    User
    Addr string
}


func main() {
    m := Boy{User{1, "zs", 20}, "bj"}
    t := reflect.TypeOf(m)
    fmt.Println(t)
    // 匿名
    fmt.Printf("%#v
", t.Field(0))
    // 值信息
    fmt.Println("%#
", reflect.ValueOf(m).Field(0))
}

修改结构体值

package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

// 修改结构体值
func SetValue(i interface{}) {
    v := reflect.ValueOf(i)
    // 指针类型重新赋值
    v = v.Elem()
    // 取字段
    f := v.FieldByName("Name")
    if f.Kind() == reflect.String {
        f.SetString("lisi")
    }
}

func main() {
    u := User{1, "zs", 20}
    SetValue(&u)
    fmt.Println(u)
}

调用方法

package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

func (u User) Hello(name string) {
    fmt.Println("hello: ", name)
}

func main() {
    u := User{1, "zs", 20}
    v := reflect.ValueOf(u)
    // 获取方法
    m := v.MethodByName("Hello")
    // 构建参数
    args := []reflect.Value{reflect.ValueOf("wangwu")}
    m.Call(args)
}

获取字段 tag

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name string `json:"name01" db:"name02"`
}

func main() {
    var s Student
    v := reflect.ValueOf(&s)
    // 类型
    t := v.Type()
    // 获取字段
    f := t.Elem().Field(0)
    // 获取tag
    fmt.Println(f.Tag.Get("json"))
    fmt.Println(f.Tag.Get("db"))
}

以上是关于Golang 反射的主要内容,如果未能解决你的问题,请参考以下文章

[golang]反射的用处--代码自动生成

golang代码片段(摘抄)

java 反射代码片段

GoLang - 有没有办法分析使用反射的代码的内存使用情况?

代码片段 - Golang 实现简单的 Web 服务器

代码片段 - Golang 实现集合操作