摘要:今天我们来学习一下 golang 中的反射,这个是 golang 语言中的一大利器。
什么是反射
Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制 --《Go 语言圣经》
为什么要用反射
需要使用反射的两个常见场景
1:有时你需要编写一个函数,但是并不知道传给你的参数类型是什么,可能是没有约定好,也可能是穿入的类型很多,这些类型并不能统一表示,这个时候反射就会用得上了。
2:有时候需要根据某些条件决定调用哪个函数,比如根据用户的输入来决定。这时就需要对函数和函数的参数进行反射,在运行期间动态的执行函数。
不使用反射的理由
1:与反射相关的代码,经常是难于阅读的,会导致代码的可读性变差。
2:Go 语言是一门静态语言,编译器在编译时期可以检查一些类型错误,但是对于反射代码是无能为力的,反射相关的代码通常只有运行的时候才会报错,可能会造成严重后果。
3:反射对性能影响比较大,会比正常代码运行速度慢一到两个数量级。
反射是如何实现的
反射类型
interface 是 Go 语言实现抽象的一个非常强大的工具。当向接口变量赋予一个实体类型的时候,接口会存储实体的类型信息,反射就是通过接口的类型信息实现的,反射建立在类型的基础上。Go 语言在 reflect 包里定义了各种类型,实现了反射的各种函数,通过它们可以在运行时检测类型的信息、改变类型的值。
反射包中有两对非常重要的函数和类型:reflect.TypeOf 能获取类型信息, reflect.ValueOf 能获取数据的运行时表示,另外两个类型是 Type 和 Value, 它们与函数是一一对应关系。
1:Type 类型
type Type interface { // Methods applicable to all types. // Name returns the type's name within its package for a defined type. // For other (non-defined) types it returns the empty string. Name() string // PkgPath returns a defined type's package path, that is, the import path // that uniquely identifies the package, such as "encoding/base64". // If the type was predeclared (string, error) or not defined (*T, struct{}, // []int, or A where A is an alias for a non-defined type), the package path // will be the empty string. PkgPath() string // Size returns the number of bytes needed to store // a value of the given type; it is analogous to unsafe.Sizeof. Size() uintptr // Kind returns the specific kind of this type. Kind() Kind // Implements reports whether the type implements the interface type u. Implements(u Type) bool // AssignableTo reports whether a value of the type is assignable to type u. AssignableTo(u Type) bool // Comparable reports whether values of this type are comparable. Comparable() bool // String returns a string representation of the type. // The string representation may use shortened package names // (e.g., base64 instead of "encoding/base64") and is not // guaranteed to be unique among types. To test for type identity, // compare the Types directly. String() string // Elem returns a type's element type. // It panics if the type's Kind is not Ptr. Elem() Type common() *rtype uncommon() *uncommonType }