golang中反射三大原则 - 【基础版】

go 语言中反射的三大原则

反射是go语言中一个非常重要的特性,go语言圣经是这样定义反射的:

go语言提供了一种机制在运行时更新变量和检查他们的值、调用他们的方法,但是在编译的时候并不知道这些变量的具体类型,这称为反射机制。

通俗来讲:就是说,我们编写的go代码,在程序编译的时候,并不知道某个变量的具体类型,但是我们可以通过在运行时利用反射的机制,来获取这个变量的类型,以及其具体的值。

那么,go语言中就提供了实现这样一个机制的一系列方法,而这些方法在reflect包中。

首先,我们来介绍一些go中reflect 包常见的一些方法,以及使用他们的方式:

  • reflect.ValueOf() 获取输入参数接口中的数据的值
  • reflect.TypeOf() 获取输入参数接口中值的类型
  • reflect.TypeOf().Kind() 用来获取值的具体类型
    - reflect.ValueOf().Field(int) 获取结构体中的第几个值
  • reflect.FieldByIndex([]int{0,1}) 层次取值
  • reflect.ValueOf().Elem() 获取原始可操作的数据

在使用上述方法之前,我们必须先了解一些基本的知识点

  • 1、空接口: go语言中接口是一种类型,而空接口类型可以保存任何值。
  • 2、interface类型特性:interface类型有个(value,type)对,而反射就是检查interface的这个(value, type)对的。具体一点说就是Go提供一组方法提取interface的value提供另一组方法提取interface的type.
  • 3、断言:格式:x.(T) : 判断x是否是T类型,一般,x是某一空接口类型,而T是某一具体类型。如果这个检查成功了,类型断言的结果是x的动态值,当然它的类型是T。换句话说,具体类型的类型断言从它的操作对象中获得具体的值。x.(type) 获取x的类型[把一个接口断言成特定的类型].

code01 : 反射第一定律:反射可以将Interface类型变量转换成反射对象

type Animal struct {
	Name string
}

type Dog struct {
	Animal
	Age int
}

func test01() {
	/**
	反射第一定律:反射可以将interface 类型变量转换城反射对象
	*/
	dog := Dog{Animal{"hello"}, 18}
	func(i interface{}) {
		// interface 类型有个(value,type)对
		t := reflect.TypeOf(i)
		v := reflect.ValueOf(i)
		fmt.Println(v, t)
	}(dog)
}

code02 : 反射第二定律:反射可以将反射对象还原成interface对象

func ReflectDemo() {
	var x float64 = 10.9
	t := reflect.TypeOf(x)	//获取x的Type 
	v := reflect.ValueOf(x) //获取x的Value
	var y float64 = v.Interface().(float64)	//v通过Interface() 函数转成interface{} 对象,interface{}对象通过断言获取float64类型具体的值
	fmt.Println(y)	
}

code03 : 反射的第三定律:反射对象可以修改,Value值必须是可以设置的

func test04() {
	/*
		反射第三定律:反射对象可修改,value值必须是可设置的
	*/
	x := 3.4
	v := reflect.ValueOf(&x)	//注意这里必须取得是x的地址,这样才可以对x进行修改
	v.Elem().SetFloat(9.9)
	fmt.Println(v) //此时v是x的地址的包装Value
	y := v.Elem()
	fmt.Println(y) //此时y对应的是x的真实值
}

*注意:下面这段程序会panic:

func test03() {
	/*
		反射第三定律:反射对象可修改,value值必须是可设置的
		x -> Value  -> interface{}
	*/
	x := 3.4
	v := reflect.ValueOf(x)
	v.SetFloat(20) //panic, v是不可修改的,
	/*
		传入 reflect.ValueOf() 函数的其实是 x 的值,而非 x 本身。即通过 v 修改其值是无法影响 x 的,所以会报错。
		如果构建 v 时使用 x 的地址就可实现修改了,但此时 v 代表的是指针地址,我们要设置的是指针所指向的内容,也即我们想要修改的是 *v 。 那怎么通过 v 修改 x 的值呢?
		reflect.Value 提供了 Elem() 方法,可以获得指针指向的 value 。
	*/
}

总结:个人理解,对于反射和断言,我们有时候会将其方法记混乱,那么我们如何来理解会更方便呢?比较直观的理解可以是这样:对于一个普通的变量x, 可以想象其值得包装类为Value, 其类型得包装类为Type, 那么,又因为interface{} 类型包含一个值得value,type对,所以,其最上层包装为interface{} , 所以我们用的函数就是将他们之间进行转换。

上面的内容比较基础,具体的可以参考其他较为详细的书籍,冲!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小吴同学GOGOGO

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

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

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

打赏作者

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

抵扣说明:

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

余额充值