【Go】go--反射

反射

  • 反射是指在程序运行时来检查变量的结构
  • 对于接口来说才有反射概念

接口

因为有接口才有反射,在理解反射前要理解下接口

  • 对于每一个接口变量,它都在底层保存了一对值(pair):接口的值和类型。
  • 接口变量的静态类型在编译期间就已经确定,并且只有一个静态类型。
var r io.Reader
r = os.Stdin
r = bufio.NewReader(r)
r = new(bytes.Buffer)

这里的变量r的静态类型只是io.Reader,正如在编译期间编译器根据这个静态变量类型来检查代码中是否有类型错误

  • 我们常常会用interface {}来做函数的变量,来接收所有类型的值,因为所有的变量都实现了interface {}的方法
package main

import (
	"fmt"
)

func main() {
	getVal(1)     // 1
	getVal("a")   // "a"
	getVal(true)  // true
}

func getVal(a interface{}) {
	fmt.Println(a)
}

正如getVal的函数接收所有类型的变量,这里的接口变量a的类型是不确定的,可以说它的类型是动态的,当需要获取外部传进来的值的类型时,反射可以解决这个问题。

反射核心概念

go中实现反射的包是reflect,其核心是reflect.Valuereflect.Type,我们分别可以通过reflect.ValueOfreflect.TypeOf得到他们。

  • reflect.TypeOf
    调用这个方法会返回reflect.Typereflect.Type是个接口,其中提供了许多有关获取类型及其他信息的方法。
package main

import (
	"fmt"
	"reflect"
)

func main() {
	v := reflect.TypeOf(3)
	fmt.Println(v)  // int
}

这里通过reflect.TypeOf获取了变量3的类型,但之前不是说对于接口才有反射吗,其实在reflect.TypeOf源码中接收的就是空接口,所以任何的值在reflect.TypeOf中被转换成了接口。

// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {
	eface := *(*emptyInterface)(unsafe.Pointer(&i))
	return toType(eface.typ)
}

package main

import (
	"fmt"
	"reflect"
)

func main() {
	type MyInt int
	var m MyInt = 5
	getVal(m)
	// main.MyInt
	// int
	getVal(1)
	// int
	// int
}

func getVal(a interface{}) {
	t := reflect.TypeOf(a)
	fmt.Println(t)
	fmt.Println(t.Kind())
}

reflect.TypeOf总是返回运行时变量的类型,可能变量在运行时值被替换,它的实时的类型就可以通过reflect.TypeOf获取。
对于Kind()方法可以帮助我们获取到被type关键字封装前的类型。

  • reflect.ValueOf

调用这个方法会返回reflect.Valuereflect.Value是个结构体,虽然在结构体内很多私有属性,但也提供了许多获取类型信息的方法。

package main

import (
	"fmt"
	"reflect"
)

func main() {
	type MyInt int
	var m MyInt = 5
	getVal(m)
	// 5
	// main.MyInt
	getVal(1)
	// 1
	// int
}

func getVal(a interface{}) {
	t := reflect.ValueOf(a)
	fmt.Println(t)
	fmt.Println(t.Type())
}

reflect.ValueOf也可以通过Type()来获取reflect.Type即变量的实时类型。

反射提供了强大的类型检查功能,但还是要谨慎使用反射:

  • 反射会降低性能,尽量在性能要求不高的地方使用
  • 反射是在运行时检查类型和值,编译期间的类型问题在编译中就会被发现,但使用反射可能会有很多意想不到的问题
  • 反射的代码并不好维护
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值