package main
// 反射不能创建方法,因此你无法在运行时实现接口。
// 反射的作用
// 大多数情况下,如果使用interface {}类型的参数调用函数,则很可能会使用反射来检查或更改参数的值。
// 反射的最常见用途是从文件或网络中序列化和反序列化数据。可以将JSON或数据库映射成指定数据结构,比如struct,slice,map等, 也可以反过来。让我们看一下如何通过查看实现JSON解组的Go标准库中的代码来完成这项工作。
// 为了将JSON字符串中的值映射到变量中,我们调用json.Unmarshal函数。它包含两个参数:
// 第一个参数是JSON,类型是[]byte
// 第二个参数是变量,即反序列化JSON生成的变量
import (
"fmt"
"reflect"
"time"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
user := User{
"jack",
20,
}
// 如果定义一个名为Foo的struct,则kind() 返回struct,Name() 返回Foo。
userType := reflect.TypeOf(user)
fmt.Println("userType:",userType," userType.Name:",userType.Name()," userType.Kind:",userType.Kind())
// userType: main.User userType.Name: User userType.Kind: struct
//如果在reflect.Type上调用一个方法,该方法与当前类型不同的类型相关联,那么程序将会崩溃。一种不错的解决方案是,始终记得使用Kind() 来判断反射值的类型
//如果变量是pointer,map,slice,channel或array,则可以使用 varType.Elem() 找到包含的类型。
//如果变量是struct,则可以使用反射来获取结构中的字段数,并获取reflect.StructField结构中包含的每个字段的结构。
//reflect.StructField中包含字段上的name,order,type和tag等信息。
firstField := userType.Field(0)
fmt.Println("firstField.Name:",firstField.Name," firstField.Type:",firstField.Type," firstField.Tag:",firstField.Tag)
// firstField.Name: Name firstField.Type: string firstField.Tag: json:"name"
//除了用来获取变量的类型之外,还可以使用反射来读取,设置或创建值。首先,使用refVal := reflect.ValueOf(val) 为变量创建一个reflect.Value实例。
//如果要使用反射来修改值,则必须获取指向变量的指针 refPtrVal := reflect.ValueOf(&val),如果不这样做,则只能使用反射读取值,但不能修改它。
userValue := reflect.ValueOf(user)
fmt.Printf("%T,%v\n",userValue,userValue)
// reflect.Value,{jack 20}
userValueElem := reflect.ValueOf(&user).Elem() // 这里必须是 &user
fmt.Println(userValueElem)
// {jack 20}
userValueElem.FieldByName("Name").SetString("apple")
fmt.Println(user)
// {apple 20}
userValue1 := reflect.ValueOf(&user)
fmt.Printf("%T,%v\n",userValue1,userValue1)
// reflect.Value,&{apple 20}
userValueElem1 := reflect.ValueOf(&user).Elem()
fmt.Println(userValueElem1)
// {apple 20}
userValueElem1.FieldByName("Name").SetString("banner")
fmt.Println(user)
// {banner 20}
// 如果要创建新值,可以使用函数调用 newPtrVal:= reflect.New(varType),传入reflect.Type。
// 这将返回一个可以修改的指针值。使用Elem().Set()如上所述。
userType = reflect.TypeOf(user)
newUser := reflect.New(userType)
newUser.Elem().FieldByName("Name").SetString("rose")
newUser.Elem().FieldByName("Age").SetInt(10)
fmt.Println(user,newUser)
// {banner 20} &{rose 10}
// 最后,可以通过调用Interface()方法返回到正常变量。
// 因为Go没有泛型,所以变量的原始类型丢失了, 所以我们需要将空接口转换为实际类型才能使用它:
user1 := User{
"aaa",
11,
}
userInterface := reflect.ValueOf(user1).Interface()
fmt.Printf("%T,%v\n",userInterface,userInterface)
// main.User,{aaa 11}
originalUser,isOK := userInterface.(User)
fmt.Printf("%T,%v\n",originalUser,originalUser)
// main.User,{aaa 11}
if isOK {
fmt.Println(originalUser.Name,originalUser.Age) // aaa 11
}
// 使用反射创建需要make才能创建类型实例
// 除了创建内置和用户定义类型的实例之外,还可以使用反射来创建通常需要make函数的实例。
// 可以使用reflect.MakeSlice,reflect.MakeMap和reflect.MakeChan函数制作slice,map或channel。
// 在所有情况下,首先需要调用创建一个reflect.Type,然后调用上面提到的这些方法来获取一个可以使用反射操作的reflect.Value。
intSlice := make([]int,0)
initMap := make(map[string]int)
sliceType := reflect.TypeOf(intSlice)
mapType := reflect.TypeOf(initMap)
reflectSlice := reflect.MakeSlice(sliceType,0,0)
reflectMap := reflect.MakeMap(mapType)
v := 10
rv := reflect.ValueOf(v)
reflectSlice = reflect.Append(reflectSlice,rv)
intSlice2 := reflectSlice.Interface().([]int)
fmt.Println(intSlice2)
//[10]
k := "hello"
rk := reflect.ValueOf(k)
reflectMap.SetMapIndex(rk,rv)
mapStringInt2 := reflectMap.Interface().(map[string]int)
fmt.Println(mapStringInt2)
// map[hello:10]
//使用make创建函数
//我们不仅可以使用反射创建存储数据的变量,还可以反使用reflect.MakeFunc函数创建新函数。
//举个栗子,如果我们想要计算一个函数执行的时长,可以像下面这样:
funcType := reflect.TypeOf(testMakeFunc)
funcValue := reflect.ValueOf(testMakeFunc)
newFunc := reflect.MakeFunc(funcType, func(args []reflect.Value) (results []reflect.Value) {
start := time.Now()
out := funcValue.Call(args)
end := time.Now()
fmt.Println(end.Sub(start))
return out
})
var count int = 1e8
newFunc.Call([]reflect.Value{reflect.ValueOf(count)})
// 100000000
// 54.330956ms
//不仅如此,我们还能借助reflect在运行时,根据某些数据来动态的生成struct,非常强大:
structValue := reflect.ValueOf(testMakeStruct(1, true, "hello world"))
fmt.Println(structValue)
// &{0 false }
}
func testMakeFunc(count int) {
sum := 0
for i := 0; i< count; i++ {
sum += 1
}
fmt.Println(sum)
}
func testMakeStruct(args ...interface{}) interface{} {
var structList []reflect.StructField
for index, value := range args {
argType := reflect.TypeOf(value)
item := reflect.StructField{
Name: fmt.Sprintf("Item%d", index),
Type: argType,
}
structList = append(structList, item)
}
structType := reflect.StructOf(structList)
structValue := reflect.New(structType)
return structValue.Interface()
}
reflect 1
最新推荐文章于 2024-01-01 08:00:00 发布