go 浅谈reflect运用

go reflect学习

  • 浅谈reflect包在结构体中的运用

    • 接口-》反射-》结构体-》结构体字段的操作(结构体字段赋值)

    • 接口-》反射-》结构体-》结构体函数(操作结构体的函数)

    • reflect.value.Elem()的作用:返回一个interface或者pointer的值

    • reflect.type.Elem()的作用:返回一个元素的类型

    • 参考代码

      package main
      
      import(
      	"fmt"
      	"time"
      	"reflect"
      	"math/rand"
      )
      
      type Student struct{
      	Pid string
      	Openid string
      	Name string
      	Age string
      }
      
      func(s Student)PrintPid(){
      	fmt.Println(s.Age)
      }
      
      func(s Student)SetOpenid(id string){
      	s.Openid = id
      	fmt.Println(s.Openid)
      }
      
      func (s Student)ReAge()string{
      	return s.Age
      }
      
      // 设置随机数值
      func SetRand()string{
      	rand.Seed(time.Now().UnixNano())
      	answers := []string{
      		"It is certain",
      		"It is decidedly so",
      		"Without a doubt",
      		"Yes definitely",
      		"You may rely on it",
      		"As I see it yes",
      		"Most likely",
      		"Outlook good",
      		"Yes",
      		"Signs point to yes",
      		"Reply hazy try again",
      		"Ask again later",
      		"Better not tell you now",
      		"Cannot predict now",
      		"Concentrate and ask again",
      		"Don't count on it",
      		"My reply is no",
      		"My sources say no",
      		"Outlook not so good",
      		"Very doubtful",
      	}
      	time.Sleep(time.Millisecond)
      	return answers[rand.Intn(len(answers))]
      }
      
      // 使用反射,查看字段并且赋值
      func reflectStructField(sPtr interface{}){
      	switch sPtr.(type) {
      	case *Student:
      		fmt.Println("指针Student类型")
      	default:
      		fmt.Println("类型不对")
      	}
      
      	rValue := reflect.ValueOf(sPtr)  //反射出一个字段
      	rE := rValue.Elem()  //指针取值
      	// 不能是指针
      	fmt.Println("struct的字段个数:",rE.NumField())
      	for i:=0;i<rE.NumField();i++{
      		f := rE.Field(i)  //指定字段
      		if f.CanSet(){
      			f.SetString(SetRand())
      		}
      	}
      }
      
      
      //使用反射,操作结构体的方法
      func reflectStructMethod(sPtr interface{}){
      	if sPtr == nil{
      		fmt.Println("sPtr is nil")
      		return
      	}
      
      	// 结构体的函数名可以根据ascll码进行排序
      	rValue := reflect.ValueOf(sPtr).Elem()
      	for i:=0;i<rValue.NumMethod();i++{
      		if i==0{
      			// 无参数
      			rValue.Method(i).Call(nil)
      		} else if i==1{
      			// 有返回值
      			data := rValue.Method(i).Call(nil)
      			fmt.Println("操作结构体有返回值函数的值",data)
      		}else if i==2{
      			// 有参数
      			var v []reflect.Value
      			v = append(v,reflect.ValueOf("天下无双"))
      			rValue.Method(i).Call(v)
      		}else{
      			fmt.Println("不会运行到这里")
      		}
      	}
      }
      
      
      func main(){
      	fmt.Println("反射学习")
      	var num float64 = 1.2345
      	pointer := reflect.ValueOf(&num)
      	value := reflect.ValueOf(num)
      	// 防止断言错误而出现panic
      	convertPointer,ok := pointer.Interface().(*float64)
      	if ok {
      		fmt.Println("convertPointer",convertPointer)
      	}
      	convertValue,ok := value.Interface().(float64)
      	if ok{
      		fmt.Println("convertValue",convertValue)
      	}
      	convertValue = 90.0
      	fmt.Println("num",num)
      
      	// 反射结构体字段的运用
      	s := &Student{"a","b","c","d"}
      	reflectStructField(s)
      	fmt.Println(s)
      
      	//反射结构体方法的运用
      	reflectStructMethod(s)
      }
      
  • 题外话:Go的反射包怎么找到对应的方法

    • 找结构体的方法

      • 第一种:反射结构体,获取结构体函数的个数。因结构体方法的排序方法是按照ascll码进行排序的,循环遍历,找到自己想要的下标值
      • 第二种:反射结构体,在已知结构体方法的名字下,通过MethodByName(string)方法获取结构体方法
    • go 方法和函数的区别

      • 方法:定义在特定类型中,通过类型的实例进行调用。
      • 函数:不可以通过类型实例,进行调用。独立存在
  • 浅谈reflect在函数适配器上的使用

    • 用法类似于C++的函数模板
    • 参考代码
    package main
    
    import(
    	"fmt"
    	"reflect"
    )
    
    // 反射制作函数适配器
    func funcAdapter(){   // C++中的函数模板
    	// 写交换两个值的函数
    	swap := func(in []reflect.Value)[]reflect.Value{
    		return []reflect.Value{in[1],in[0]}
    	}
    
    	// 函数适配器
    	makeSwap := func(fptr interface{}){
    		fn := reflect.ValueOf(fptr).Elem()
    		v := reflect.MakeFunc(fn.Type(),swap)
    		fn.Set(v)
    	}
    
    	// 函数执行
    	var intSwap func(int,int)(int,int)
    	makeSwap(&intSwap)
    	fmt.Println(intSwap(0,1))
    
    	var floatSwap func(float64,float64)(float64,float64)
    	makeSwap(&floatSwap)
    	fmt.Println(floatSwap(7.56,8.89))
    }
    
    func main(){
    	// 反射适配器的应用
    	funcAdapter()
    }
    
  • 浅谈reflect包反射函数

    • 思路和reflect反射结构体,查找方法的思路类似。

    • 参考代码

      package main
      
      import(
      	"fmt"
      	"reflect"
      )
      
      // 无参数
      func reflectFuncStudy1(){
      	fmt.Println("无参数的学习")
      }
      
      // 有参数
      func reflectFuncStudy2(data string){
      	fmt.Println(data)
      }
      
      // 函数有返回值
      func reflectFuncStudy3()string{
      	return "函数有返回值"
      }
      func main(){
      	// 反射函数(函数也是一种类型)
      	// 查找函数进行反射
      	f1 := reflect.ValueOf(reflectFuncStudy1)  //无参数
      	f1.Call(nil)
      
      	f2 := reflect.ValueOf(reflectFuncStudy2)  //有参数
      	params := make([]reflect.Value,0)
      	params = append(params,reflect.ValueOf("有参数学习"))
      	f2.Call(params)
      
      	f3 := reflect.ValueOf(reflectFuncStudy3)
      	rdata := f3.Call(nil)[0].Interface()  //Call返回的是一个value的切片
      	sdata,ok := rdata.(string)
      	if ok {
      		fmt.Println("sdata = ",sdata)
      		sdata = "哈哈哈" + sdata
      		fmt.Println(sdata)
      	}
      }
      
  • 参考学习资料

posted @ 2019-10-08 01:04  Myuniverse  阅读(650)  评论(0编辑  收藏  举报