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()方
*/

原文地址:https://www.cnblogs.com/liuzhanghao/p/15363479.html