Golang学习+深入(十四)-反射

目录

一、概述

1、反射

1.1、反射注意细节

1.2、案例


一、概述

1、反射

  1. 反射可以在运行时动态获取变量的各种信息,比如变量的类型,类别
  2. 如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
  3. 通过反射,可以修改变量的值,可以调用关联的方法
  4. 通过反射,需要import ("reflect")
import "reflect":reflect包实现了运行时反射,允许程序操作任意类型的对象。
type Type:Type类型用来表示一个go类型。
func ValueOf(i interface{}) Value:ValueOf返回一个初始化为i接口保管的具体值的Value,ValueOf(nil)返回Value零值。
  1. reflect.TypeOf(变量名):获取变量的类型,返回reflect.Type类型
  2. reflect.ValueOf(变量名):获取变量的值,返回reflect.Value类型 reflect.Value是一个结构体类型。
  3. 变量、interface{}和reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到。
package main
import (
	"fmt"
	"reflect"
)

func reflectTest01(b interface{}){
	//获取reflect.Type
	rTyp := reflect.TypeOf(b)
	fmt.Println("rTyp=",rTyp)
	//获取reflect.Value
	rVal := reflect.ValueOf(b)
	fmt.Printf("rVal=%v rVal type=%T\n",rVal,rVal)
	//将rVal转成interface{}
	iv := rVal.Interface()
	num :=iv.(int)
	fmt.Println("num=",num)
}

func reflectTest02(b interface{}){
	//获取reflect.Type
	rTyp := reflect.TypeOf(b)
	fmt.Println("rTyp=",rTyp)
	//获取reflect.Value
	rVal := reflect.ValueOf(b)
	fmt.Printf("rVal=%v rVal type=%T\n",rVal,rVal)
	//获取Kind
	//1.
	kind1 := rTyp.Kind()
	//2.
	kind2 :=rVal.Kind()
	fmt.Printf("kind=%v kind=%v\n",kind1,kind2)
	//将rVal转成interface{}
	iv := rVal.Interface()
	stu,ok :=iv.(Student)
	if ok {
		fmt.Println("stu=",stu)
	}
}

type Student struct{
	Name string
	Age int
}

func main(){
	var num int =100
	reflectTest01(num)

	stu :=Student{
		Name:"小米",
		Age:10,
	}
	reflectTest02(stu)
}

1.1、反射注意细节

  1. reflect.Value.Kind,获取变量的类别,返回的是一个常量
Kind代表Type类型值表示的具体分类。零值表示非法分类。
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
)
  1. Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的
  • 比如:var num int =10 num的Type是int,Kind也是int
  • 比如:var stu Student stu的Type是 包名.Student,Kind是struct
  1. 通过反射可以让变量在interface{}和Reflect.Value之间相互转换。
  2. 使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么就应该使用reflect.Value(x).Int(),而不能使用其他的,否则报panic
  3. 通过反射来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem()方法。
package main
import (
	"fmt"
	"reflect"
)
func reflectTest01(b interface{}){
	//获取reflect.Value
	rVal := reflect.ValueOf(b)
	fmt.Printf("rVal kind=%v\n",rVal.Kind())//rVal kind=ptr
	//将rVal转成interface{}
	rVal.Elem().SetInt(20)
}
func main(){
	var num int =100
	reflectTest01(&num)
	fmt.Println("num",num)//num 20
}
  1. reflect.Value.Elem()应该如何理解?
func (v Value) Elem() Value:Elem返回v持有的接口保管的值的Value封装,
或者v持有的指针指向的值的Value封装。
package main
import (
	"fmt"
	"reflect"
)
func main(){
	var num int =100
	rVal := reflect.ValueOf(&num)
	rVal.Elem().SetInt(200)
	fmt.Printf("%v\n",num)
	//rVal.Elem()用于获取指针指向变量,类似于
	var num1=100
	var b *int =&num1
	*b=200
	fmt.Printf("%v\n",num1)
}

1.2、案例

package main
import (
	"fmt"
	"reflect"
)

type Monster struct {
	Name string `json:"name"`
	Age int `json:"monster_age"`
	Score float32
	Sex string
}

func (s Monster) Print(){
	fmt.Println("--start Print")
	fmt.Println(s)
	fmt.Println("--end")
}

func (s Monster) GetSum(n1,n2 int) int{
	return n1+n2
}

func reflectTest01(b interface{}){
	//获取reflect.Type
	rTyp := reflect.TypeOf(b)
	//获取reflect.Value
	rVal := reflect.ValueOf(b)
	kd :=rVal.Kind()
	if kd != reflect.Struct {
		fmt.Println("not struct")
		return
	}

	num := rVal.NumField()
	fmt.Printf("struct has %d fields\n",num)
	//遍历结构体的所有字段
	for i:=0;i<num;i++{
		fmt.Printf("field %d: 值为=%v\n",i,rVal.Field(i))
		tagVal := rTyp.Field(i).Tag.Get("json")
		//有标签就显示,无,不显示
		if tagVal != ""{
			fmt.Printf("field %d: tag为=%v\n",i,tagVal)
		}
	}

	numMethod := rVal.NumMethod()
	fmt.Printf("struct has %d Methods\n",numMethod)
	//方法的排序默认是按照 函数名的排序(ASCII码的大小排序)
	rVal.Method(1).Call(nil)//获取第二个方法,调用它

	//调用结构体的第一个方法Method(0)
	var params []reflect.Value
	params=append(params,reflect.ValueOf(10))
	params=append(params,reflect.ValueOf(40))
	res := rVal.Method(0).Call(params)//传入参数是[]reflect.Value
	fmt.Println("res=",res[0].Int())//返回结果,返回的结果是 []reflect.Value
}

func main(){
	var b Monster=Monster{
		Name:"小明",
		Age:40,
		Score:30.0,
		Sex:"男",
	}
	reflectTest01(b)
}

Golang学习+深入(十五)-网络编程

干我们这行,啥时候懈怠,就意味着长进的停止,长进的停止就意味着被淘汰,只能往前冲,直到凤凰涅槃的一天!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杀神lwz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值