015.反射

1.初识反射

/*
reflect包:反射;反射代码是不安全的,尽量少用
*/

func main() {

	//1.正常的业务代码:获取变量的类型和值
	num := 1
	fmt.Println("类型:", reflect.TypeOf(num)) // 类型: int
	fmt.Println("值:", reflect.ValueOf(num)) // 值: 1

	var a int
	fmt.Scan(&a)
	//2.通过反射获取对象的类型和值
	value := reflect.ValueOf(a) //返回一个value对象
	//判断类型进行不同的操作 : value.Kind()获取变量类型
	if value.Kind() == reflect.Float64 {
		fmt.Println(value.Float())
	}
	if value.Kind() == reflect.Int {
		fmt.Println(value.Int())
	}
	if value.Kind() == reflect.String {
		fmt.Println(value.String())
	}
}

2.静态变量和动态变量

在反射过程中: 编译的时候就知道变量类型的叫静态类型变量,运行时才知道类型的变量叫动态类型的变量

1.静态类型:声明变量的时候赋予类型的 var name string var age int

2.动态类型:在运行时可能会发生变化 var A any A = 10 A = "abc" //变量A类型发生了变化

3.为什么要用反射

1.我们编写一个函数,但是没约定好入参,不知道传递过来的参数是什么类型,可以使用反射

2.我们定义了一个可以传递任意类型的函数,可以通过反射判断类型进行不同的处理

4.为什么不建议使用反射

1.和反射相关的代码,可读性太低

2.Go语言是静态类型的语言,正常代码开发编译器可以找出编译期的错误;反射代码可能存在运行时才报的错误,一旦panic项目就会停止

3.反射的性能很低,相较于正常的开发,至少慢几个数量级

5.反射获取对象信息

1.获取变量的类型:reflect.TypeOf(变量名) ->Type
    1.1:获取变量的种类:Type.Kind() 
    1.2:获取变量字段的数量:Type.NumField()
       获取变量的字段名:Type.Field(i)
    1.3获取变量方法的数量:Type.NumMethod()
       获取变量的方法名:Type.Method(i)
2.获取变量的值:reflect.ValueOf(变量名) ->Value
    2.1:获取字段对应的值:Value.Field(i).Interface()
//定义一个结构体

type User struct {
	Name   string
	Age    int
	Gender string
}

// 定义结构体的方法:方法名一定要大写,否则反射获取不到

func (user User) Say(msg string) {
	fmt.Println(user.Name, "say:", msg)
}

func (user User) PrintInfo() {
	fmt.Printf("姓名:%s,年龄:%d,性别,%s", user.Name, user.Age, user.Gender)
}

func main() {
	user := User{"张三", 23, "男"}
	reflectGetInfo(user)
}

// 通过反射获取传递的对象信息
func reflectGetInfo(v any) {
	//1.获取对象的类型
	getType := reflect.TypeOf(v)
	fmt.Println("类型:", getType.Name())   //类型: User
	fmt.Println("上级种类:", getType.Kind()) //上级种类: struct

	//2.获取对象字段信息
	getValue := reflect.ValueOf(v)
	for i := 0; i < getType.NumField(); i++ {
		//获取字段的类型
		field := getType.Field(i)
		//获取字段的值
		value := getValue.Field(i).Interface()
		fmt.Printf("字段名:%s,字段类型:%s,字段值:%v\n", field.Name, field.Type, value)
	}
	//3.获取对象的方法
	for i := 0; i < getType.NumMethod(); i++ {
		method := getType.Method(i)
		fmt.Printf("方法名:%s,方法类型:%s\n", method.Name, method.Type)
	}
}

6.反射修改变量的值

type Stu struct {
	Name   string
	Age    int
	Gender string
}

func main() {
	a := Stu{"张三", 23, "男"}
	//获取指针
	value := reflect.ValueOf(&a)
	if value.Kind() == reflect.Ptr {
		//获取指针对象
		newValue := value.Elem()
		//判断该类型是否可以修改
		if newValue.CanSet() {
			if newValue.Kind() == reflect.Int {
				newValue.SetInt(168)
			}
			if newValue.Kind() == reflect.String {
				newValue.SetString("测试字符串")
			}
			if newValue.Kind() == reflect.Float64 {
				newValue.SetFloat(3.14)
			}
			if newValue.Kind() == reflect.Struct {
				newValue.FieldByName("Name").SetString("李四")
				newValue.FieldByName("Age").SetInt(24)
			}
		}
	}
	fmt.Println(a)
}

7.反射调用函数


// 无参无返回值
func fun1() {
	fmt.Println("无参无返回值函数")
}

// 有参有返回值
func fun2(a string, b int) {
	fmt.Printf("有参无返回值,a:%s,b:%d\n", a, b)
}

// 有参无返回值
func fun3(a, b int) string {
	fmt.Printf("有参有返回值,a:%d,b:%d\n", a, b)
	return "aaa"
}
func main() {
	//无参无返回值函数调用
	value1 := reflect.ValueOf(fun1)
	fmt.Println(value1.Kind(), value1.Type())
	value1.Call(nil)
	fmt.Println("======")
	// 有参有返回值函数调用
	value2 := reflect.ValueOf(fun2)
	fmt.Println(value2.Kind(), value2.Type())
	args1 := make([]reflect.Value, 2)
	args1[0] = reflect.ValueOf("str")
	args1[1] = reflect.ValueOf(12)
	value2.Call(args1)
	fmt.Println("======")
	// 有参无返回值函数调用
	value3 := reflect.ValueOf(fun3)
	fmt.Println(value3.Kind(), value3.Type())
	args2 := make([]reflect.Value, 2)
	args2[0] = reflect.ValueOf(34)
	args2[1] = reflect.ValueOf(12)
	res := value3.Call(args2)
	fmt.Println("返回值:", res)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值