Golang从入门到精通(十七):Golang反射
2017-12-14 10:58
337 查看
Go语言类型
Go语言是静态类型的编程语言,所有数据的类型在编译期确定了。而且 Go 语言中即使是底层存的是一个类型,声明的类型不一样,也要强制转换才能互用。
例如:
type MyInt int var i int var j MyInt
这里的 i 和 j 类型不一致 ,如果需要进行比较或者加减运算 ,需要强制转换类型。
注意:在 Go 语言里面没有隐式转换,遇到不同类型想互用,只能进行强制类型转换。
空接口
Go语言空interface(interface{})不包含任何的method,因此所有的类型都实现了空interface,空interface在我们需要存储任意类型的数值的时候相当有用。我们通过一个例子来看一下空接口的强大:package main import ( "fmt" ) func main() { slice := make([]interface{}, 10) map1 := make(map[string]string) map2 := make(map[string]int) map2["TaskID"] = 1 map1["Command"] = "ping" map3 := make(map[string]map[string]string) map3["mapvalue"] = map1 slice[0] = map2 slice[1] = map1 slice[3] = map3 fmt.Println(slice[0]) fmt.Println(slice[1]) fmt.Println(slice[3]) }
这段代码声明了一个空接口的slice,这意味着它的值可以是任意类型,然后我们声明了两个map,一个是map[string]string,一个是map[string]int,然后在声明一个map的map类型,将这三个类型赋值给slice,使得slice可以存贮各种不同类型的数据,想想看,一个可变数组中,存储了一个key为string类型,value为int类型的map,又存储了一个key为string类型,value为string类型的map,还存储了一个map的map。
go的反射机制是要通过接口来进行的,而类似于Java的Object的空接口可以和任何类型进行交互,因此对基本数据类型等的反射也直接利用了这一特点。
接口类型变量转换为反射类型对象
package main import ( "fmt" "reflect" ) func main() { var circle float64 = 6.28 var icir interface{} icir = circle fmt.Println("Reflect : circle.Value = ", reflect.ValueOf(icir)) fmt.Println("Reflect : circle.Type = ", reflect.TypeOf(icir)) }
上面代码的执行结果如下:
Reflect : circle.Value = 6.28 Reflect : circle.Type = float64
可以看到ValueOf和TypeOf的参数都是空接口,因此,这说明可以直接使用变量传进去,比如:
package main import ( "fmt" "reflect" ) func main() { var circle float64 = 6.28 fmt.Println("Reflect : circle.Value = ", reflect.ValueOf(circle)) fmt.Println("Reflect : circle.Type = ", reflect.TypeOf(circle)) }
反射类型对象转换为接口类型变量
这个其实是上面运算的逆过程,简单例子代码如下:package main import ( "fmt" "reflect" ) func main() { var circle float64 = 6.28 var icir interface{} icir = circle valueref := reflect.ValueOf(icir) fmt.Println(valueref) fmt.Println(valueref.Interface()) y := valueref.Interface().(float64) fmt.Println(y) }
用反射进行变量修改
利用反射修改变量时,首先需要使用CanSet函数确认变量是否是可修改的。简单代码示例如下:package main import ( "fmt" "reflect" ) func main() { var circle float64 = 6.28 value := reflect.ValueOf(circle) fmt.Println("Reflect : value = ", value) fmt.Println("Settability of value : ", value.CanSet()) value2 := reflect.ValueOf(&circle) fmt.Println("Settability of value : ", value2.CanSet()) value3 := value2.Elem() fmt.Println("Settability of value : ", value3.CanSet()) value3.SetFloat(3.14) fmt.Println("Value of value3: ", value3) fmt.Println("value of circle: ", circle) }
性能代价
Go语言反射在带来“方便”的同时,会造成问题:它会带来很大的性能损失。直接赋值和反射赋值在实际使用中性能差异挺大,所以如果对性能要求较高,那么请谨慎使用反射。相关文章推荐
- 黑马程序员_笔记十七_基础增强之反射
- [Golang语言社区]--提高 golang 的反射性能
- golang反射初试
- 跟着刚哥梳理java知识点——反射和代理(十七)
- [golang]反射的用处--代码自动生成
- Golang-interface(四 反射)
- Golang从入门到精通(十八):Golang并发编程之Goroutine
- golang实现简单的反射demo
- Java从入门到精通 - 反射Field
- Golang教程:(十七)方法
- Golang从入门到精通(十九):Golang并发编程之Channel
- golang 反射
- golang reflect 反射机制
- golang 提高反射性能
- (十七)Core Java 反射的使用(框架的开发原理) (115)
- golang反射与反射三法则
- golang使用反射创建对象
- Golang 反射
- golang的反射机制
- golang基础-反射获取(基础数据、结构体)、操作(基本类型、结构体、指针)、反射获取Tag