什么是反射
Go语言中的反射是指在程序运行时检查程序的结构,比如变量的类型、方法的签名等。Go语言的反射包是reflect。通过反射,你可以动态地检查类型信息、获取字段和方法、调用方法等。
反射可以在运行时动态获取变量的各种信息,比如变量的类型、值等
如果是结构体,还可以获取到结构体本身的各种信息,比如结构体的字段、方法
通过反射,还可以修改变量的值、调用方法
使用反射,需要引入一个包:reflect,它定义了内个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value两部分组成,并且reflect 包提供了 reflect.Typ!alue和Type.Of和 reflect.ValueOf 两个函数来获取任意对象的 V
(Type)和种类(Kind)的区别。编程中,使用最多的是类型,但在反射中,当需要区分一个品种的类型时在使用反射时,需要首先理解类型.就会用到种类(Kind)。
package main
import (
"fmt"
"reflect"
)
func main() {
var a float64 = 3.14
fmt.Println(reflect.TypeOf(a))
fmt.Println(reflect.ValueOf(a))
v := reflect.ValueOf(a)
if v.Kind() == reflect.Float64 {
fmt.Println("v.kind() is float64")
}
fmt.Println(v.Type())
fmt.Println(v.Float())
}
1.反射的应用场景
需要反射的2个常见场景:
- 1.有时你需要编写一个函数,但是并不知道传给你的参数类型是什么,可能是没约定好;也可能是传入的类型很多,这时反射就会用的上了。
- 2.有时候需要根据某些条件决定调用哪个函数,比如根据户的输入来决定。这时就需要对函数和函数的参数进行反函数。
但是对于反射,还是有几点不太建议使用反射的理由:
- 1、与反射相关的代码,经常是难以阅读的。在软件工程中代码可读性也是一个非常重要的指标。
- 2、Go语言作为一门静态语言,编码过程中,编译器能提发现一些类型错误,但是对于反射代码是无能为力的。所可能会运行很久,才会出错,这时候经常是直接panic,可会造成严重的后果。
- 3、反射对性能影响还是比较大的,比正常代码运行速度慢一到两个数量级。所以,对于一个项目中处于运行效率关钱位置的代码,尽量避免使用反射特性。
2. 反射获取变量信息
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
Sex string
}
func (user User) Say(msg string) {
fmt.Println("user说", msg)
}
func main() {
user := User{Name: "xiaolong", Age: 18, Sex: "男"}
reflectGetInfo(user)
}
func reflectGetInfo(input interface{}) {
//获取参数类型
getType := reflect.TypeOf(input)
fmt.Println("type is", getType.Name())
fmt.Println("kind is", getType.Kind())
//获取值
getValue := reflect.ValueOf(input)
fmt.Println("getValue is", getValue)
//通过反射获取反射结果内的字段与方法
for i := 0; i < getType.NumField(); i++ {
filed := getType.Field(i)
value := getValue.Field(i).Interface()
fmt.Println(filed.Name, filed.Type, value)
}
for i := 0; i < getType.NumMethod(); i++ {
method := getType.Method(i)
fmt.Println(method.Name, method.Type)
}
}
3.反射修改对象的值
package main
import (
"fmt"
"reflect"
)
func main() {
var num float64 = 1.23
point := reflect.ValueOf(&num) //想要通过指针修改值,需要传入指针
newValue := point.Elem()
fmt.Println(newValue.Kind())
fmt.Println(newValue.Type())
fmt.Println(newValue.CanSet())
if newValue.CanSet() {
newValue.SetFloat(3.14)
}
fmt.Println(num)
}
修改结构体
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
Sex string
}
func (user User) Say(msg string) {
fmt.Println("user说", msg)
}
func main() {
user := User{Name: "xiaolong", Age: 18, Sex: "男"}
fmt.Println(user)
newValue := reflect.ValueOf(&user)
if newValue.Kind() == reflect.Ptr { //首先是指针
valueTemp := newValue.Elem()
if valueTemp.CanSet() {
valueTemp.FieldByName("Name").SetString("dalong")
valueTemp.FieldByName("Age").SetInt(38)
}
}
fmt.Println(user)
}
4.反射调用方法函数
方法调用文章来源:https://www.toymoban.com/news/detail-785570.html
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
Sex string
}
func (user User) Say(msg string) {
fmt.Println("user说", msg)
}
func (user User) GetInfo() {
fmt.Println("user 信息", user.Name, user.Age)
}
func main() {
user := User{Name: "xiaolong", Age: 18, Sex: "男"}
//reflectGetInfo(user)
fmt.Println(user)
//无参数方法调用
value := reflect.ValueOf(user)
value.MethodByName("GetInfo").Call(nil)
//有参数方法调用
args := make([]reflect.Value, 1)
args[0] = reflect.ValueOf("反射调用")
value.MethodByName("Say").Call(args)
}
函数调用文章来源地址https://www.toymoban.com/news/detail-785570.html
package main
import (
"fmt"
"reflect"
)
func main() {
v1 := reflect.ValueOf(func1)
v1.Call(nil)
v2 := reflect.ValueOf(func2)
args := make([]reflect.Value, 2)
args[0] = reflect.ValueOf(1)
args[1] = reflect.ValueOf("gagaga")
v2.Call(args)
v3 := reflect.ValueOf(func3)
args1 := make([]reflect.Value, 2)
args1[0] = reflect.ValueOf(1)
args1[1] = reflect.ValueOf("gagaga")
res := v3.Call(args1)
fmt.Println(res[0].Interface())
}
func func1() {
fmt.Println("无参数fun1")
}
func func2(i int, s string) {
fmt.Println("有参数fun2", i, s)
}
func func3(i int, s string) string {
fmt.Println("有参数fun3", i, s)
return s
}
到了这里,关于GO基础进阶篇 (十二)、反射的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!