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

反射介绍

2. 反射与空接口

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

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

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

3. 怎么分析?

            A. 内置包 reflect

            B. 获取类型信息: reflect.TypeOf

            C. 获取值信息: reflect.ValueOf

4. 基本数据类型分析

package main

import (
    "fmt"
    "reflect"
)

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

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

package main
import (
    "fmt"
    "reflect"
)
func main() {
    var x float64 = 3.4
    t := reflect.TypeOf(x)
    fmt.Println("type:", t.Kind())
}
//Go的变量类型
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
)

6. 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()) 

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

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()) 

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)

v.SetFloat(6.8)
fmt.Println("value:", v.Float()) 

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

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()) 

10.通过反射设置变量的值

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()) 

11. 获取结构体类型相关信息

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\n", i,
        t.Field(i).Name, f.Type(), f.Interface())
    }
}

12. 获取结构体类型相关信息

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\n", i,
        t.Field(i).Name, f.Type(), f.Interface())
    }
}

13. 设置结构体相关字段的值

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\n", i,
        t.Elem().Field(i).Name, f.Type(), f.Interface())
    }
}

14. 获取结构体的方法信息

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\n", i, f.Name, f.Type)
    }
}

15. 调用结构体中的方法

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\n", s)
}

16. 获取结构体中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"))
}

反射总结以及应用场景

17. 反射总结

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

18. 应用场景

            A. 序列化和反序列化,比如json, protobuf等各种数据协议

            B. 各种数据库的ORM, 比如gorm,sqlx等数据库中间件

            C. 配置文件解析相关的库, 比如yaml、ini等

这些场景,我们实现都不直到数据的具体类型,所以要用反射。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值