reflect 1

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()
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值