golang 反射demo

反射

代码在运行过程中,动态获取修改代码自身的能力,就是反射。

为啥用反射

对于静态类型语言,为了提高灵活性,有时在代码里允许传入多种类型变量,编译的时候不清楚会用哪一种,只有代码执行的时候才能动态感知到。通过反射只能获取 Golang 内置类型,用类型断言则可以获取所有类型(包括用户自定义类型)。

示例

通过反射查看变量类型和值

package main

import (
    "fmt"
    "reflect"
)

type People struct {
    Name string
    Age int
    No int
}
type Student struct {
    SNo int
    People
}

func main() {
    i := 333
    f(i)
    
    s := Student{1, People{"kika", 33, 1}}
    f(s)
    
    p := People{"lisi", 22, 123}
    f(p)
    
    f(&p)
}

func f(i interface{}) {
    t := reflect.TypeOf(i)  // 真实类型,包括用户自定义类型
    v := reflect.ValueOf(i)
    k := v.Kind()           // golang 内置类别,例如 map,struct,string,bool,int 等
    if k == reflect.Ptr {
        e := v.Elem()       // 如果传入的是指针,通过 Elem() 拿到指向的值
        fmt.Println("Elem is:", e)
    }
    fmt.Printf("type is: %s\nvalue is: %v\nkind is: %s\n\n", t, v, k)
    fmt.Println()
}

输出:

type is: int
value is: 333
kind is: int


type is: main.Student
value is: {1 {kika 33 1}}
kind is: struct


type is: main.People
value is: {lisi 22 123}
kind is: struct


Elem is: {lisi 22 123}
type is: *main.People
value is: &{lisi 22 123}
kind is: ptr

通过反射把变量转为具体类型的值

通过 reflect.ValueOf(i) 得到的 reflect.Value 类型不是基本类型,需要再调用 reflect 包的具体类型转换函数得到具体类型,从而实现跟类型断言一样的效果。只支持 golang 的内置类型转换。

例如:

func (v Value) Int() int64
func (v Value) OverflowInt(x int64) bool
func (v Value) Uint() uint64
func (v Value) OverflowUint(x uint64) bool
func (v Value) Float() float64
func (v Value) OverflowFloat(x float64) bool
func (v Value) Complex() complex128
func (v Value) OverflowComplex(x complex128) bool
func (v Value) Bytes() []byte
func (v Value) String() string

示例:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    a := 3
    f(a)
}

func f(i interface{}) {
    rVal := reflect.ValueOf(i)
    fmt.Printf("%T, %v\n", rVal, rVal)
    // fmt.Println(rVal + 3) // invalid operation: rVal + 3 (mismatched types reflect.Value and int)
    rInt := rVal.Int()
    fmt.Println(rInt + 3)
}

通过反射修改变量值(需要传地址)

package main

import (
    "fmt"
    "reflect"
)

func main() {
    s := "hello world"
    fmt.Println(s)
    reflect.ValueOf(&s).Elem().SetString("hello golang")
    fmt.Println(s)
}

通过反射操作结构体

可以查看结构体元素、方法,并调用方法:

package main

import (
    "fmt"
    "reflect"
)

type People struct {
    Name string `json:"name"`
    Age int
    No int
}
func (p People) Eat() {
    fmt.Println("People eating")
}

func main() {
    p := People{"kika", 29, 33332222}
    fmt.Println(p)
    rVal := reflect.ValueOf(p)
    rType := reflect.TypeOf(p)
    nf := rVal.NumField()
    fmt.Println("NumField is: ", nf)  // 字段个数
    for i := 0; i < nf; i++ {
        iv := rVal.Field(i)
        fmt.Print(iv)
        tag := rType.Field(i).Tag.Get("json")
        if tag != "" {
            fmt.Print(", tag is:", tag)
        }
        fmt.Println()
    }
    
    nm := rVal.NumMethod()
    fmt.Println("NumMethod is: ", nm)  // 方法个数
    for i := 0; i < nm; i++ {
        iv := rVal.Method(i)
        fmt.Printf("Method is: %v\n", iv)
        ret := iv.Call([]reflect.Value{}) // 调用方法
        fmt.Println(ret)
    }
}
package main

import (
    "fmt"
    "reflect"
)

type M struct{}
type In struct{}
type Out struct{}
 
func (m *M) Example(in In) Out {
    fmt.Println("call Example in M")
	return Out{}
}
func main() {
	v := reflect.ValueOf(&M{})
	m := v.MethodByName("Example")
	in := m.Type().In(0)
	out := m.Type().Out(0)
	fmt.Println(in, out)
       
	inVal := reflect.New(in).Elem()
	rtn := m.Call([]reflect.Value{inVal})
	fmt.Println(rtn[0])
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值