zoukankan      html  css  js  c++  java
  • 197. go reflect 反射基础

    复制到自己的编辑器, 从main函数看

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func reflectTest01(b interface{}) {
    	//通过反射获取的传入的变量的 type , kind, 值
    	//1. 先获取到 reflect.Type
    	rtype := reflect.TypeOf(b)
    	fmt.Println(rtype)
    	//2. 获取到 reflect.Value
    	rval := reflect.ValueOf(b)
    	n2 := 2 + rval.Int()
    	fmt.Println("n2=", n2)
    	//下面我们将 rVal 转成 interface{}
    	iv := rval.Interface()
    	//将 interface{} 通过断言转成需要的类型
    	num2 := iv.(int)
    	fmt.Println("num2=", num2)
    }
    
    type Student struct {
    	Name string
    	Age  int
    }
    
    func reflectTest02(b interface{}) {
    	//通过反射获取的传入的变量的 type , kind, 值
    	//1. 先获取到 reflect.Type
    	rtype := reflect.TypeOf(b)
    	fmt.Println(rtype)
    	//2. 获取到 reflect.Value
    	rval := reflect.ValueOf(b)
    
    	// 将 rVal 转成 interface{}
    	iv := rval.Interface()
    	fmt.Printf("iv=%v iv type=%T
    ", iv, iv)
    
    	// 使用类型推断将interface转换为需要的类型
    	stu, ok := iv.(Student)
    	if ok {
    		fmt.Printf("stu.name=%v
    ", stu.Name)
    	}
    }
    
    func reflectTest03(b interface{}) {
    	v1 := reflect.ValueOf(b)
    	fmt.Printf("val type=%T
    ", v1)
    	v1.Elem().SetInt(100) // 通过反射设置值
    	fmt.Printf("val=%v
    ", v1)
    
    }
    
    func reflectTest04(b interface{}) {
    	rtype := reflect.TypeOf(b) // main.Student
    	val := reflect.ValueOf(b)  // { 0}
    
    	fmt.Printf("%v
    ", rtype)
    	fmt.Printf("%v
    ", val)
    	fmt.Printf("%v
    ", val.Kind()) // struct
    
    	v2 := val.Interface()
    	fmt.Printf("%v
    ", v2) // 将reflect.Value -> interface{}
    	v3, ok := v2.(float64) // 将interface{} -> float64
    	if ok {
    		fmt.Println(v3)
    		fmt.Printf("%v, %T", v3, v3)
    	}
    }
    
    type Monster struct {
    	Name  string  `json:"name"`
    	Age   int     `json:"age"`
    	Score float64 `json:"score"`
    	Sex   string
    }
    
    func (this Monster) GetSum(n1, n2 int) int {
    	return n1 + n2
    }
    
    func (this Monster) Set(name string, age int, score float64, sex string) {
    	this.Name = name
    	this.Age = age
    	this.Score = score
    	this.Sex = sex
    }
    
    func (this Monster) Print() {
    	println("------start---------")
    	fmt.Println(this)
    	println("------end---------")
    }
    
    func reflectTest05(a interface{}) {
    	typ := reflect.TypeOf(a)  // 获取类型
    	val := reflect.ValueOf(a) // 获取值
    	kd := val.Kind()          // 获取kind
    	fmt.Println(kd, "---------------------------")
    	if kd != reflect.Struct {
    		fmt.Println("expect struct, actul is: ", kd)
    		return
    	}
    
    	num := val.NumField() // 获取字段数目
    	fmt.Printf("struct has %d files
    ", num)
    
    	// 遍历字段
    	for i := 0; i < num; i++ {
    		fmt.Printf("Filed %d: 值为=%v
    ", i, val.Field(i))
    		// 获取struct标签, 通过reflect.Type 来获取tag标签的值
    		tagVal := typ.Field(i).Tag.Get("json")
    		// 如果该字段于tag标签的显示, 否则就不显示
    		if tagVal != "" {
    			fmt.Printf("filed %d, tag为=%v
    ", i, tagVal)
    		}
    	}
    
    	// 获取结构的多少方法
    	numOfMethod := val.NumMethod()
    	fmt.Printf("struct had %d methods
    ", numOfMethod)
    	//var params []reflect.Value
    	//方法的排序默认是按照 函数名的排序(ASCII 码)
    	val.Method(1).Call(nil) // 获取第二个方法, 调用它
    
    	// 调用结构体的第一个方法 Method(0)
    	var params []reflect.Value
    	params = append(params, reflect.ValueOf(10))
    	params = append(params, reflect.ValueOf(40))
    
    	// 传入的参数是[]reflect.Value, 返回reflect.value
    	res := val.Method(0).Call(params)
    	fmt.Println("res=", res) // []reflect.value */
    }
    
    func reflectTest06(a interface{}) {
    	typ := reflect.TypeOf(a)  // 获取类型
    	val := reflect.ValueOf(a) // 获取值
    	kd := val.Kind()          // 获取kind
    	fmt.Println(kd, "---------------------------")
    	if kd != reflect.Struct {
    		fmt.Println("expect struct, actul is: ", kd)
    		return
    	}
    
    	num := typ.NumField() // 获取字段数目
    	fmt.Printf("struct has %d files
    ", num)
    
    	// 遍历字段
    	for i := 0; i < num; i++ {
    		filed := typ.Field(i)
    		value := val.Field(i).Interface()
    		fmt.Printf("%s: %v = %v
    ", filed.Name, filed.Type, value)
    	}
    
    	// 获取结构的多少方法
    	for i := 0; i < typ.NumMethod(); i++ {
    		m := typ.Method(i)
    		fmt.Printf("%s : %v
    ", m.Name, m.Type)
    	}
    }
    
    func test1() {
    	slice := []int{1, 2, 3, 4, 5}
    	m := make(map[int]int)
    	for key, val := range slice {
    
    		fmt.Println(key, val, &val)
    		m[key] = val
    	}
    	for key := range m {
    		// 都是5, 为什么?
    		// 可以理解为上面的val始终使用的是同一个地址, 值一致在被修改而地址不变(面试题)
    		fmt.Println(m[key])
    	}
    }
    
    func main() {
    	// var num int = 100
    	// reflectTest01(num) // (基本数据类型、interface{}、reflect.Value)进行反射的基本操作
    
    	// stu := Student{
    	// 	Name: "tom",
    	// 	Age:  12,
    	// }
    	// reflectTest02(stu) // (基本数据类型、interface{}、reflect.Value)进行反射的基本操作
    
    	// var a = 10
    	// reflectTest03(&a) // 通过反射修改值, 需要传入指针
    	// fmt.Println(a)
    	/*
    		reflect.Value.Elem()   var num = 10; var b *int = &num; *b = 100
    	*/
    
    	// var f1 = 10.2
    	// // var f1 = Student{}
    	// reflectTest04(f1) // 练习 给你一个变量 var v float64 = 1.2 , 请使用反射来得到它的 reflect.Value, 然后获取对应Type,Kind 和值,并将 reflect.Value 转换成 interface{} , 再将 interface{} 转换成 float64.
    
    	// var m1 = Monster{
    	// 	Name:  "牛魔王",
    	// 	Age:   12,
    	// 	Score: 12.2,
    	// 	Sex:   "femal",
    	// }
    	// reflectTest05(m1) //通过获取方法, 字段等 m1的方法绑定时需要和Monster, 而不是*Monster, 要不然获取不出来方法
    
    	// https://studygolang.com/articles/12348?fr=sidebar  具体仔细阅读这个博客
    	// reflectTest06(m1) // 获取字段类型以及方法类型
    	test1() // 面试题
    }
    
    /*
    1) reflect.Value.Kind,获取变量的类别,返回的是一个常量
    2) Type 和 Kind 的区别
    Type 是类型, Kind 是类别, Type 和 Kind 可能是相同的,也可能是不同的.
    比如: var num int = 10 num 的 Type 是 int , Kind 也是 int
    比如: var stu Student stu 的 Type 是 pkg1.Student , Kind 是 struct
    3) 通过 反射可以将变量在interface{}和Reflet.Value之间转换
    	变量<---------> interface{} <------------> reflect.Value
    4)式用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,
    那么就应该使用reflect.Value(x).Int(),而不能使用其它的,否则报panic
    5) 通过反射的来修改变量, 注意当使用 SetXxx 方法来设置需要通过对应的指针类型来完成, 这样
    才能改变传入的变量的值, 同时需要使用到 reflect.Value.Elem()方
    */
    
    
  • 相关阅读:
    ASP.NET编程中非常有用的例子
    打包样式资源
    9.使用类的2个注意点
    面向对象案例
    super必须放到子类this之前
    PHP:根据二维数组中的某个字段进行排序
    Vuex的五个核心属性
    利用按钮控制listview的当前选择项,滚动条跟随动
    c#通过进程名字获取进程路径
    判断客户端是否安装realplayer
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/15363479.html
Copyright © 2011-2022 走看看