1.go的结构体分析
本文是在go1.19.10的背景下,作为记录用,为了防止遗忘。
1.结构体函数的分析
测试代码
type User struct {
Id int
Name string
Age int
}
func (u User) TestUserNoPtr(name string) {
u.Name = name
}
func (u *User) TestUserPtr(name string) {
u.Name = name
}
func TestReflectStruct(t *testing.T) {
userOnePtr := &User{1, "no-modify", 25}
userOnePtr.TestUserNoPtr("modify")
fmt.Printf("struct(*user) func(u User) u=%v \n", userOnePtr)
userTwoPtr := &User{1, "no-modify", 25}
userTwoPtr.TestUserPtr("modify")
fmt.Printf("struct(*user) func(u *User) u=%v\n", userTwoPtr)
userOne := User{1, "no-modify", 25}
userOne.TestUserNoPtr("modify")
fmt.Printf("struct(user) func(u User) u=%v\n", userOne)
userTwo := User{1, "no-modify", 25}
userTwo.TestUserPtr("modify")
fmt.Printf("struct(user) func(u *User) u=%v\n", userTwo)
}
注意上面的测试函数,并没有用非常标准的测试函数检测,而是直接打印出来,这样是为了结果更加清晰
最后的结果
struct(*user) func(u User) u=&{1 no-modify 25}
struct(*user) func(u *User) u=&{1 modify 25}
struct(user) func(u User) u={1 no-modify 25}
struct(user) func(u *User) u={1 modify 25}
从其中可以看出结构体指针可以调用自己的receiver是指针和非指针的函数,同样结构体也可以调用调用自己的receiver是指针和非指针的函数,但是数值的真正的改变只和receiver有关,是指针才会改变。
2.结构体函数的反射的分析
测试代码
//和前面的一样,加个接口
type IUser interface {
TestUserNoPtr(name string)
TestUserPtr(name string)
}
func TestReflectStruct(t *testing.T) {
userPtr := &User{1, "no-modify", 25}
userPtrType := reflect.TypeOf(userPtr)
userPtrValue := reflect.ValueOf(userPtr)
for i := 0; i < userPtrType.NumMethod(); i++ {
m := userPtrType.Method(i)
fmt.Printf("%v: %v\n", m, m.IsExported())
}
if userPtrType.Implements(reflect.TypeOf((*IUser)(nil)).Elem()) {
if f, ok := userPtrValue.Interface().(IUser); ok {
f.TestUserNoPtr("modify")
fmt.Printf("struct(*user) func(u User) u=%v \n", userPtr)
f.TestUserPtr("modify")
fmt.Printf("struct(*user) func(u *User) u=%v \n", userPtr)
}
}
fmt.Println()
user := User{1, "no-modify", 25}
userType := reflect.TypeOf(user)
for i := 0; i < userType.NumMethod(); i++ {
m := userType.Method(i)
fmt.Printf("%v: %v\n", m, m.IsExported())
}
}
测试结果
{TestUserNoPtr func(*main_test.User, string) <func(*main_test.User, string) Value> 0}: true
{TestUserPtr func(*main_test.User, string) <func(*main_test.User, string) Value> 1}: true
struct(*user) func(u User) u=&{1 no-modify 25}
struct(*user) func(u *User) u=&{1 modify 25}
{TestUserNoPtr func(main_test.User, string) <func(main_test.User, string) Value> 0}: true
反射出来的,结构体指针可以调用那两个函数,而且是否修改也和receiver是否是指针有关,但是结构体就不能调用receiver是指针的,因为它只有一个函数。
3.嵌套结构体函数的分析
测试代码1
//注意*User是指针
type UserChild struct {
*User
Id int
Name string
Age int
}
func TestReflectStruct(t *testing.T) {
userOnePtr := &UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userOnePtr.TestUserNoPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u User) u=%v \n", userOnePtr.User)
userTwoPtr := &UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwoPtr.TestUserPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u *User) u=%v\n", userTwoPtr.User)
userOne := UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userOne.TestUserNoPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u User) u=%v\n", userOne.User)
userTwo := UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwo.TestUserPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u *User) u=%v\n", userTwo.User)
}
结果1
struct(*UserChild) fileld(*User) func(u User) u=&{1 no-modify 25}
struct(*UserChild) fileld(*User) func(u *User) u=&{1 modify 25}
struct(UserChild) fileld(*User) func(u User) u=&{1 no-modify 25}
struct(UserChild) fileld(*User) func(u *User) u=&{1 modify 25}
这个结果和第一个标题的结果一样,如果我们将*user,换成user,就是嵌入结构体不用指针
type UserChild struct {
User
Id int
Name string
Age int
}
func TestReflectStruct(t *testing.T) {
userOnePtr := &UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userOnePtr.TestUserNoPtr("modify")
fmt.Printf("struct(*UserChild) fileld(User) func(u User) u=%v \n", userOnePtr.User)
userTwoPtr := &UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwoPtr.TestUserPtr("modify")
fmt.Printf("struct(*UserChild) fileld(User) func(u *User) u=%v\n", userTwoPtr.User)
userOne := UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userOne.TestUserNoPtr("modify")
fmt.Printf("struct(UserChild) fileld(User) func(u User) u=%v\n", userOne.User)
userTwo := UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwo.TestUserPtr("modify")
fmt.Printf("struct(UserChild) fileld(User) func(u *User) u=%v\n", userTwo.User)
}
struct(*UserChild) fileld(User) func(u User) u={1 no-modify 25}
struct(*UserChild) fileld(User) func(u *User) u={1 modify 25}
struct(UserChild) fileld(User) func(u User) u={1 no-modify 25}
struct(UserChild) fileld(User) func(u *User) u={1 modify 25}
结果2和结果1一样,也就是说嵌入结果是否是指针,不影响底层函数,它只和receiver是否是指针才能修改
4.嵌入结构体的反射
测试代码1
func TestReflectStruct(t *testing.T) {
userPtr := &UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userPtrType := reflect.TypeOf(userPtr)
userPtrValue := reflect.ValueOf(userPtr)
for i := 0; i < userPtrType.NumMethod(); i++ {
m := userPtrType.Method(i)
fmt.Printf("%v: %v\n", m, m.IsExported())
}
if userPtrType.Implements(reflect.TypeOf((*IUser)(nil)).Elem()) {
if f, ok := userPtrValue.Interface().(IUser); ok {
f.TestUserNoPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u User) u=%v \n", userPtr.User)
f.TestUserPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u *User) u=%v \n", userPtr.User)
}
}
fmt.Println()
user := UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userType := reflect.TypeOf(user)
userValue := reflect.ValueOf(user)
for i := 0; i < userType.NumMethod(); i++ {
m := userType.Method(i)
fmt.Printf("%v: %v\n", m, m.IsExported())
}
if userType.Implements(reflect.TypeOf((*IUser)(nil)).Elem()) {
if f, ok := userValue.Interface().(IUser); ok {
f.TestUserNoPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u User) u=%v \n", user.User)
f.TestUserPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u *User) u=%v \n", user.User)
}
}
}
结果1为
{TestUserNoPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 1}: true
struct(*UserChild) fileld(*User) func(u User) u=&{1 no-modify 25}
struct(*UserChild) fileld(*User) func(u *User) u=&{1 modify 25}
{TestUserNoPtr func(main_test.UserChild, string) <func(main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(main_test.UserChild, string) <func(main_test.UserChild, string) Value> 1}: true
struct(UserChild) fileld(*User) func(u User) u=&{1 no-modify 25}
struct(UserChild) fileld(*User) func(u *User) u=&{1 modify 25}
如果我们将如果我们将*user,换成user,再看一下结果2
{TestUserNoPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 1}: true
struct(*UserChild) fileld(User) func(u User) u={1 no-modify 25}
struct(*UserChild) fileld(User) func(u *User) u={1 modify 25}
{TestUserNoPtr func(main_test.UserChild, string) <func(main_test.UserChild, string) Value> 0}: true
如果UserChild是指针,嵌入结构体是否是指针,都可以原始的指针来调用,
如果UserChild不是指针,user不是指针这按照原始来调用,因为只有一个函数,如果是*user是指针,则可以按照正常来调用。
总过反射来调用函数和直接通过结构体来调用函数,就是反射不能调用非指针的接口函数
5.结构体函数的覆盖
测试案例1
func (u User) TestUserNoPtr(name string) {
fmt.Println("has execute User TestUserNoPtr")
u.Name = name
}
func (u *User) TestUserPtr(name string) {
fmt.Println("has execute User TestUserPtr")
u.Name = name
}
//加入覆盖的函数
func (u *UserChild) TestUserNoPtr(name string) {
fmt.Println("has execute UserChild TestUserNoPtr")
u.Name = name
}
func (u *UserChild) TestUserPtr(name string) {
fmt.Println("has execute UserChild TestUserPtr")
u.Name = name
}
func TestReflectStruct(t *testing.T) {
userOnePtr := &UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userOnePtr.TestUserNoPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u User) u=%v c=%v\n", userOnePtr.User, userOnePtr)
userTwoPtr := &UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwoPtr.TestUserPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u *User) u=%v c=%v\n", userTwoPtr.User, userTwoPtr)
userOne := UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userOne.TestUserNoPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u User) u=%v c=%v\n", userOne.User, userOne)
userTwo := UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwo.TestUserPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u *User) u=%v c=%v\n", userTwo.User, userTwo)
}
//测试结果
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(*User) func(u User) u=&{1 no-modify 25} c=&{0xc000096100 1 modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(*User) func(u *User) u=&{1 no-modify 25} c=&{0xc000096140 1 modify 25}
has execute UserChild TestUserNoPtr
struct(UserChild) fileld(*User) func(u User) u=&{1 no-modify 25} c={0xc000096180 1 modify 25}
has execute UserChild TestUserPtr
struct(UserChild) fileld(*User) func(u *User) u=&{1 no-modify 25} c={0xc0000961c0 1 modify 25}
func TestReflectStructFunc(t *testing.T) {
userPtr := &UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userPtrType := reflect.TypeOf(userPtr)
userPtrValue := reflect.ValueOf(userPtr)
for i := 0; i < userPtrType.NumMethod(); i++ {
m := userPtrType.Method(i)
fmt.Printf("%v: %v\n", m, m.IsExported())
}
if userPtrType.Implements(reflect.TypeOf((*IUser)(nil)).Elem()) {
if f, ok := userPtrValue.Interface().(IUser); ok {
f.TestUserNoPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u User) u=%v c=%v\n", userPtr.User, userPtr)
//这里的函数应该分开测,毕竟上面的可能已经改变,但是我们只观测执行函数的逻辑和覆盖的逻辑
f.TestUserPtr("modify")
fmt.Printf("struct(*UserChild) fileld(*User) func(u *User) u=%v c=%v\n", userPtr.User, userPtr)
}
}
fmt.Println()
user := UserChild{&User{1, "no-modify", 25}, 1, "no-modify", 25}
userType := reflect.TypeOf(user)
userValue := reflect.ValueOf(user)
for i := 0; i < userType.NumMethod(); i++ {
m := userType.Method(i)
fmt.Printf("%v: %v\n", m, m.IsExported())
}
if userType.Implements(reflect.TypeOf((*IUser)(nil)).Elem()) {
if f, ok := userValue.Interface().(IUser); ok {
f.TestUserNoPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u User) u=%v c=%v\n", user.User, user)
//这里的函数应该分开测,毕竟上面的可能已经改变,但是我们只观测执行函数的逻辑和覆盖的逻辑
f.TestUserPtr("modify")
fmt.Printf("struct(UserChild) fileld(*User) func(u *User) u=%v c=%v\n", user.User, user)
}
}
}
//测试结果2
{TestUserNoPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 1}: true
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(*User) func(u User) u=&{1 no-modify 25} c=&{0xc0001de0e0 1 modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(*User) func(u *User) u=&{1 no-modify 25} c=&{0xc0001de0e0 1 modify 25}
//下面的直接没有方法,也验证了反射的不能调用指针的接口
测试结果2
//将上面的指针去掉
func (u UserChild) TestUserNoPtr(name string) {
fmt.Println("has execute UserChild TestUserNoPtr")
u.Name = name
}
func (u UserChild) TestUserPtr(name string) {
fmt.Println("has execute UserChild TestUserPtr")
u.Name = name
}
//测试结果
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(*User) func(u User) u=&{1 no-modify 25} c=&{0xc00030a220 1 no-modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(*User) func(u *User) u=&{1 no-modify 25} c=&{0xc00030a260 1 no-modify 25}
has execute UserChild TestUserNoPtr
struct(UserChild) fileld(*User) func(u User) u=&{1 no-modify 25} c={0xc00030a320 1 no-modify 25}
has execute UserChild TestUserPtr
struct(UserChild) fileld(*User) func(u *User) u=&{1 no-modify 25} c={0xc00030a360 1 no-modify 25}
//和上面一样,用反射测
{TestUserNoPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 1}: true
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(*User) func(u User) u=&{1 no-modify 25} c=&{0xc00008e100 1 no-modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(*User) func(u *User) u=&{1 no-modify 25} c=&{0xc00008e100 1 no-modify 25}
{TestUserNoPtr func(main_test.UserChild, string) <func(main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(main_test.UserChild, string) <func(main_test.UserChild, string) Value> 1}: true
has execute UserChild TestUserNoPtr
struct(UserChild) fileld(*User) func(u User) u=&{1 no-modify 25} c={0xc00008e1a0 1 no-modify 25}
has execute UserChild TestUserPtr
struct(UserChild) fileld(*User) func(u *User) u=&{1 no-modify 25} c={0xc00008e1a0 1 no-modify 25}
测试结果3
func (u *User) TestUserPtr(name string) {
fmt.Println("has execute User TestUserPtr")
u.Name = name
}
func (u *UserChild) TestUserNoPtr(name string) {
fmt.Println("has execute UserChild TestUserNoPtr")
u.Name = name
}
//将改为非指针
type UserChild struct {
User
Id int
Name string
Age int
}
func TestReflectStruct(t *testing.T) {
userOnePtr := &UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userOnePtr.TestUserNoPtr("modify")
fmt.Printf("struct(*UserChild) fileld(User) func(u User) u=%v c=%v\n", userOnePtr.User, userOnePtr)
userTwoPtr := &UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwoPtr.TestUserPtr("modify")
fmt.Printf("struct(*UserChild) fileld(User) func(u *User) u=%v c=%v\n", userTwoPtr.User, userTwoPtr)
userOne := UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userOne.TestUserNoPtr("modify")
fmt.Printf("struct(UserChild) fileld(User) func(u User) u=%v c=%v\n", userOne.User, userOne)
userTwo := UserChild{User{1, "no-modify", 25}, 1, "no-modify", 25}
userTwo.TestUserPtr("modify")
fmt.Printf("struct(UserChild) fileld(User) func(u *User) u=%v c=%v\n", userTwo.User, userTwo)
}
//测试结果
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(User) func(u User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(User) func(u *User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 modify 25}
has execute UserChild TestUserNoPtr
struct(UserChild) fileld(User) func(u User) u={1 no-modify 25} c={{1 no-modify 25} 1 modify 25}
has execute UserChild TestUserPtr
struct(UserChild) fileld(User) func(u *User) u={1 no-modify 25} c={{1 no-modify 25} 1 modify 25}
//和上面一样,用反射测
{TestUserNoPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 1}: true
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(User) func(u User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(User) func(u *User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 modify 25}
测试结果4
//将测试3的改为
func (u UserChild) TestUserNoPtr(name string) {
fmt.Println("has execute UserChild TestUserNoPtr")
u.Name = name
}
func (u UserChild) TestUserPtr(name string) {
fmt.Println("has execute UserChild TestUserPtr")
u.Name = name
}
//测试结果为
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(User) func(u User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 no-modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(User) func(u *User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 no-modify 25}
has execute UserChild TestUserNoPtr
struct(UserChild) fileld(User) func(u User) u={1 no-modify 25} c={{1 no-modify 25} 1 no-modify 25}
has execute UserChild TestUserPtr
struct(UserChild) fileld(User) func(u *User) u={1 no-modify 25} c={{1 no-modify 25} 1 no-modify 25}
//和上面一样,用反射测
{TestUserNoPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(*main_test.UserChild, string) <func(*main_test.UserChild, string) Value> 1}: true
has execute UserChild TestUserNoPtr
struct(*UserChild) fileld(User) func(u User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 no-modify 25}
has execute UserChild TestUserPtr
struct(*UserChild) fileld(User) func(u *User) u={1 no-modify 25} c=&{{1 no-modify 25} 1 no-modify 25}
{TestUserNoPtr func(main_test.UserChild, string) <func(main_test.UserChild, string) Value> 0}: true
{TestUserPtr func(main_test.UserChild, string) <func(main_test.UserChild, string) Value> 1}: true
has execute UserChild TestUserNoPtr
struct(UserChild) fileld(User) func(u User) u={1 no-modify 25} c={{1 no-modify 25} 1 no-modify 25}
has execute UserChild TestUserPtr
struct(UserChild) fileld(User) func(u *User) u={1 no-modify 25} c={{1 no-modify 25} 1 no-modify 25}
通过上面的测试,没得到有用的信息,有些人可能会自以为的
func (u *UserChild) TestUserNoPtr(name string) {
func (u User) TestUserNoPtr(name string)
对于UserChild来说,上面的两个函数,指针的调用上面的接口,非指针调用下面的接口,即函数名相同就覆盖,和receiver的是否指针没有关系,和上面测的user是一样的,是否修改只看receiver是否指针有关,和嵌入结构体是否指针无关,最后反射出来的和实际的结构体调用是有区别的,结构体反射出来的,不能调用receiver是指针的函数,切记!!!!
2.结构体反射的实际应用
1.map ->struct的转换
在实际的应用中,网络二进制[]byte进行传输,比如将json格式,probuf格式,binary库的write函数的1字节对齐的格式等等,还有gorm其他的将struct转换对应自己能分析的数据,都要用到反射。对于map到struct的函数转换,我们首先第一想到的就是深搜,因为上面的基本上的应用都是深搜的解决办法,因为struct能嵌套结构体,本身slice能嵌套slice,map也是,也可以互相嵌套,所以对于生成struct,slice,map我们就写一个生成函数,递归调用自己,其他基础类型,直接赋值,作为退出的条件,这就是map->struct的思想
func PraseStruct(m map[string]any, t reflect.Type, value reflect.Value) {
for i := 0; i < t.NumField(); i++ {
//value.Field(i).SetInt(int64(i + 1))
//去掉多余的指针,这个要自己new数据,多级指针的话
//structFiled := t.Field(i)
//filedTag := structFiled.Tag
//filedType := structFiled.Type
//filedValue := value.Field(i)
//
//finalType := filedType
//finalValue := filedValue
//for finalValue.Kind() == reflect.Ptr {
// finalValue = finalValue.Elem()
//
//}
//finalType = finalValue.Type()
structFiled := t.Field(i)
filedTag := structFiled.Tag
filedType := structFiled.Type
filedValue := value.Field(i)
finalType := filedType
//finalValue := filedValue
for finalType.Kind() == reflect.Ptr {
finalType = finalType.Elem()
}
if filedType.Kind() == reflect.Ptr && filedValue.Kind() == reflect.Ptr { //反向赋值
middle := reflect.New(finalType).Elem()
middleType := filedType
for middleType.Kind() == reflect.Ptr {
p := reflect.New(middle.Type())
p.Elem().Set(middle)
middle = p
middleType = middleType.Elem()
}
filedValue.Set(middle)
}
finalValue := filedValue
for finalValue.Kind() == reflect.Ptr {
finalValue = finalValue.Elem()
}
switch finalValue.Kind() {
case reflect.Struct:
{
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
if structFiled.Anonymous { //是否是匿名结构体
}
PraseStruct(v.(map[string]interface{}), finalType, finalValue)
//fmt.Println(finalType.Name())
if finalType.Name() == "BaseData" {
//两个成员函数不能带指针,如果有一个带,它只会有没有指针的成员函数,要注意
//这里的finalType=reflect.Typeof(BaseData)
//for i := 0; i < finalType.NumMethod(); i++ {
// m := finalType.Method(i)
// finalType.Method(i)
//
// fmt.Printf("%v,%v\n", m, m.IsExported())
//}
//
//if finalType.Implements(reflect.TypeOf((*BaseDataName)(nil)).Elem()) {//如果两个有一个带指针,这里就不会判断正确
// f, ok := finalValue.Interface().(BaseDataName) //如果两个有一个带指针,这里就不会ok
// if ok {
// f.PtrPrefixName()
// }
//}
//这里的finalType=reflect.Typeof(*BaseData),指针都可以调用
ptrValue := reflect.New(finalType)
ptrType := ptrValue.Type()
for i := 0; i < ptrType.NumMethod(); i++ {
m := ptrType.Method(i)
ptrType.Method(i)
fmt.Printf("%v,%v\n", m, m.IsExported())
}
if ptrType.Implements(reflect.TypeOf((*BaseDataName)(nil)).Elem()) { //如果两个有一个带指针,这里就不会判断正确
f, ok := ptrValue.Interface().(BaseDataName) //如果两个有一个带指针,这里就不会ok
if ok {
f.PtrPrefixName()
}
}
}
}
case reflect.Bool:
{
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
if _, okb := v.(bool); !okb { //的类型不一致
return
}
if !finalValue.CanSet() {
return
}
finalValue.SetBool(v.(bool))
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
{
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
vValue := reflect.ValueOf(v)
if vValue.Kind() != reflect.Int && vValue.Kind() != reflect.Int8 &&
vValue.Kind() != reflect.Int16 && vValue.Kind() != reflect.Int32 &&
vValue.Kind() != reflect.Int64 { //的类型不一致
return
}
if !finalValue.CanSet() {
return
}
switch vValue.Kind() {
case reflect.Int8:
finalValue.SetInt(int64(v.(int8)))
case reflect.Int16:
finalValue.SetInt(int64(v.(int16)))
case reflect.Int32:
finalValue.SetInt(int64(v.(int32)))
case reflect.Int64:
finalValue.SetInt(v.(int64))
default:
fmt.Println("no unkown type")
}
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
{
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
//vValue := reflect.ValueOf(v)
//if vValue.Kind() != reflect.Uint && vValue.Kind() != reflect.Uint8 &&
// vValue.Kind() != reflect.Uint16 && vValue.Kind() != reflect.Uint32 &&
// vValue.Kind() != reflect.Uint64 { //的类型不一致
// return
//}
//
//switch vValue.Kind() {
//case reflect.Uint8:
// finalValue.SetUint(uint64(v.(uint8)))
//case reflect.Uint16:
// finalValue.SetUint(uint64(v.(uint16)))
//case reflect.Uint32:
// finalValue.SetUint(uint64(v.(uint32)))
//case reflect.Uint64:
// finalValue.SetUint(v.(uint64))
//default:
// fmt.Println("no unkown type")
//}
if !finalValue.CanSet() {
return
}
switch data := v.(type) {
case uint8:
finalValue.SetUint(uint64(data))
case uint16:
finalValue.SetUint(uint64(data))
case uint32:
finalValue.SetUint(uint64(data))
case uint64:
finalValue.SetUint(data)
default:
fmt.Println("no unkown type")
}
}
case reflect.Float32, reflect.Float64:
{
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
vValue := reflect.ValueOf(v)
if vValue.Kind() != reflect.Float32 && vValue.Kind() != reflect.Float64 { //的类型不一致
return
}
if !finalValue.CanSet() {
return
}
if vValue.Kind() == reflect.Float32 {
finalValue.SetFloat(float64(v.(float32)))
} else {
finalValue.SetFloat(v.(float64))
}
}
case reflect.String:
{
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
if !finalValue.CanSet() {
return
}
switch data := v.(type) {
case string:
finalValue.SetString(data)
case []byte:
finalValue.SetString(string(data))
default:
fmt.Println("no unkown type")
}
}
case reflect.Slice:
{
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
vValue := reflect.ValueOf(v)
if vValue.Kind() != reflect.Slice {
return
}
if vValue.IsNil() { //map里的slice为空
return
}
if !finalValue.CanSet() {
return
}
targetValue, err := GenerateSlice(finalType, vValue)
if err != nil {
return
}
finalValue.Set(targetValue)
}
case reflect.Map:
tagName, ok := filedTag.Lookup("cesi")
if !ok { //判断 omitemoty,required的规则
return
}
v, okv := m[tagName]
if !okv { //判断default的规则
return
}
vValue := reflect.ValueOf(v)
if vValue.Kind() != reflect.Map {
return
}
targetValue, err := GenerateMap(filedType.Key(), filedType.Elem(), vValue)
if err != nil {
return
}
if !finalValue.CanSet() {
return
}
if !targetValue.Type().AssignableTo(finalValue.Type()) {
return
}
finalValue.Set(targetValue)
}
}
}
func GenerateSlice(sliceType reflect.Type, mapSlice reflect.Value) (reflect.Value, error) {
newSlice := reflect.MakeSlice(sliceType, mapSlice.Len(), mapSlice.Cap())
if mapSlice.Len() == 0 {
return newSlice, nil
}
baseElem := sliceType.Elem()
endElem := baseElem
for endElem.Kind() == reflect.Ptr {
endElem = endElem.Elem()
}
//一个一个元素赋值
for i := 0; i < mapSlice.Len(); i++ {
elemValue := newSlice.Index(i)
mapElemValue := mapSlice.Index(i)
switch endElem.Kind() {
case reflect.Struct:
{
v, ok := mapElemValue.Interface().(map[string]any)
if !ok {
return reflect.ValueOf(struct{}{}), errors.New("mapElemValue.Interface().(map[string]any)")
}
newStruct := reflect.New(endElem)
endValue := newStruct
for endValue.Kind() == reflect.Ptr {
endValue = endValue.Elem()
}
PraseStruct(v, endValue.Type(), endValue)
//[]***elem的struct的多级指针
middleValue := newStruct.Elem()
if baseElem.Kind() == reflect.Ptr {
middleType := baseElem
for middleType.Kind() == reflect.Ptr {
p := reflect.New(middleValue.Type())
p.Elem().Set(middleValue)
middleValue = p
middleType = middleType.Elem()
}
}
elemValue.Set(middleValue)
}
case reflect.Slice:
{
fmt.Println(endElem, mapElemValue.Type())
target, err := GenerateSlice(endElem, mapElemValue)
if err != nil {
return reflect.ValueOf(struct{}{}), err
}
elemValue.Set(target)
}
case reflect.Map:
{
v, ok := mapElemValue.Interface().(map[string]any)
if !ok {
return reflect.ValueOf(struct{}{}), errors.New("mapElemValue.Interface().(map[string]any)")
}
target, err := GenerateMap(endElem.Key(), endElem.Elem(), reflect.ValueOf(v)) //不能用keyValue直接赋值,因为它是any,kind是接口类型
if err != nil {
return reflect.ValueOf(struct{}{}), err
}
elemValue.Set(target)
}
default:
{
//常规类型的多级指针,真正的赋值
startElemType := elemValue.Type()
baseElemType := startElemType
for baseElemType.Kind() == reflect.Ptr {
baseElemType = baseElemType.Elem()
}
if startElemType.Kind() == reflect.Ptr {
middleElem := reflect.New(baseElemType).Elem()
middleType := startElemType
for middleType.Kind() == reflect.Ptr {
p := reflect.New(middleElem.Type())
p.Elem().Set(middleElem)
middleElem = p
middleType = middleType.Elem()
}
elemValue.Set(middleElem)
}
endValue := elemValue
for endValue.Kind() == reflect.Ptr {
endValue = endValue.Elem()
}
switch data := mapElemValue.Interface().(type) {
case bool, string, uint8, uint16, uint32, uint64, uint, int, int8, int32, int64, float32, float64:
{
realValue := reflect.ValueOf(data)
if realValue.Kind() != endValue.Kind() {
return reflect.ValueOf(struct{}{}), errors.New("realValue.Kind() != endValue.Kind()")
}
endValue.Set(realValue)
}
default:
{
//这里只能具体类型赋值具体类型,如果要any赋值到具体类型,必须和struct一样,每个元素要中断
if !endValue.Type().AssignableTo(mapElemValue.Type()) {
return reflect.ValueOf(struct{}{}), errors.New("endValue.Type().AssignableTo(mapElemValue.Type())")
}
endValue.Set(mapElemValue)
}
}
}
}
}
return newSlice, nil
}
func GenerateMap(keyType, elemType reflect.Type, mapValue reflect.Value) (reflect.Value, error) {
generateMapType := reflect.MapOf(keyType, elemType)
mapType := mapValue.Type()
if generateMapType == mapType {
return mapValue, nil
}
//map的key的type要相等
if keyType != mapType.Key() {
return reflect.ValueOf(struct{}{}), errors.New("key type is not queal")
}
target := reflect.MakeMapWithSize(generateMapType, mapValue.Len())
endMapElem := elemType
for endMapElem.Kind() == reflect.Ptr {
endMapElem = endMapElem.Elem()
}
for _, key := range mapValue.MapKeys() {
keyValue := mapValue.MapIndex(key)
keyValueVV := keyValue.Interface()
switch endMapElem.Kind() {
case reflect.Slice:
{
targetElem, err := GenerateSlice(endMapElem, keyValue)
if err != nil {
return reflect.ValueOf(struct{}{}), err
}
target.SetMapIndex(key, targetElem)
}
case reflect.Struct:
{
v, ok := keyValue.Interface().(map[string]any)
if !ok {
return reflect.ValueOf(struct{}{}), errors.New("mapValue.Interface().(map[string]any)")
}
newStruct := reflect.New(endMapElem)
endValue := newStruct
for endValue.Kind() == reflect.Ptr {
endValue = endValue.Elem()
}
PraseStruct(v, endValue.Type(), endValue)
middleValue := newStruct.Elem()
if elemType.Kind() == reflect.Ptr {
middleType := elemType
for middleType.Kind() == reflect.Ptr {
p := reflect.New(middleValue.Type())
p.Elem().Set(middleValue)
middleValue = p
middleType = middleType.Elem()
}
}
target.SetMapIndex(key, middleValue)
}
case reflect.Map:
{
v, ok := keyValue.Interface().(map[string]any)
if !ok {
return reflect.ValueOf(struct{}{}), errors.New("mapValue.Interface().(map[string]any)")
}
targetElem, err := GenerateMap(endMapElem.Key(), endMapElem.Elem(), reflect.ValueOf(v)) //不能用keyValue直接赋值,因为它是any,kind是接口类型
if err != nil {
return reflect.ValueOf(struct{}{}), err
}
target.SetMapIndex(key, targetElem)
}
default:
{
switch data := keyValueVV.(type) {
case bool, string, uint8, uint16, uint32, uint64, uint, int, int8, int32, int64, float32, float64:
{
realValue := reflect.ValueOf(data)
if endMapElem.Kind() != realValue.Kind() {
return reflect.ValueOf(struct{}{}), errors.New("endMapElem.Kind()!=realValue.Kind()")
}
target.SetMapIndex(key, realValue)
}
default: //any -> any
{
if !keyValue.Type().AssignableTo(endMapElem) {
return reflect.ValueOf(struct{}{}), errors.New("!keyValue.Type().AssignableTo(endMapElem)")
}
target.SetMapIndex(key, keyValue)
}
}
}
}
}
return target, nil
}
func MarshalStruct(m map[string]any, v any) {
if v == nil {
fmt.Errorf("var s struct is not pointer")
}
//去掉多余的指针
structType := reflect.TypeOf(v)
structValue := reflect.ValueOf(v)
finalType := structType
finalValue := structValue
for finalValue.Kind() == reflect.Ptr {
finalValue = finalValue.Elem()
}
finalType = finalValue.Type()
if finalValue.Kind() == reflect.Struct {
PraseStruct(m, finalType, finalValue)
}
//打印
//printValue := structValue
//for printValue.Kind() == reflect.Ptr {
// printValue = printValue.Elem()
// fmt.Println(printValue)
//}
}
type BaseData struct {
Bool bool `cesi:"Bool"`
Int8 int8 `cesi:"Int8"`
Int16 int16 `cesi:"Int16"`
Int32 int32 `cesi:"Int32"`
Int64 **int64 `cesi:"Int64"`
UInt8 uint8 `cesi:"UInt8"`
UInt16 uint16 `cesi:"UInt16"`
UInt32 uint32 `cesi:"UInt32"`
UInt64 uint64 `cesi:"UInt64"`
Float32 **float32 `cesi:"Float32"`
Float64 float64 `cesi:"Float64"`
}
type BaseDataName interface {
PtrPrefixName()
PrefixName()
}
func (b *BaseData) PtrPrefixName() {
fmt.Println("b*BaseData")
b.Int32 = 99999
}
func (b BaseData) PrefixName() {
fmt.Println("b*BaseData")
b.Int32 = 99999
}
type MiddleData struct {
RealBaseData *BaseData `cesi:"RealBaseData"`
String string `cesi:"String"`
SliceByte **[]**string `cesi:"SliceByte"`
SliceAny []string `cesi:"SliceAny"` /* **string any*/
SliceStruct []***BaseData `cesi:"SliceStruct"`
SliceSlice [][]**int `cesi:"SliceSlice"`
SliceMap []map[string]int `cesi:"SliceMap"`
Map map[string]int `cesi:"Map"`
MapAny map[string]int `cesi:"MapAny"`
MapStruct map[string]***BaseData `cesi:"MapStruct"`
MapMap map[string]map[string]int32 `cesi:"MapMap"`
MapSlice map[string][]string `cesi:"MapSlice"`
}
type StructData struct {
//BaseData
RealMiddleData ***MiddleData `cesi:"MiddleData"`
//Bool bool `cesi:"Bool"`
//Int8 int8 `cesi:"Int8"`
//Int16 int16 `cesi:"Int16"`
//Int32 int32 `cesi:"Int32"`
//Int64 int64 `cesi:"Int64"`
//
//UInt8 int8 `cesi:"UInt8"`
//UInt16 int16 `cesi:"UInt16"`
//UInt32 int32 `cesi:"UInt32"`
//UInt64 int64 `cesi:"UInt64"`
//
//Float32 float32 `cesi:"Float32"`
//Float64 float64 `cesi:"Float64"`
}
func TestReflectStructPtr(t *testing.T) {
mBaseData := map[string]interface{}{
"Bool": true,
"Int8": int8(-1),
"Int16": int16(-2),
"Int32": int32(-3),
"Int64": int64(-4),
"UInt8": uint8(1),
"UInt16": uint16(2),
"UInt32": uint32(3),
"UInt64": uint64(4),
"Float32": float32(1.99),
"Float64": float64(2.9999),
}
mm := map[string]interface{}{
"RealBaseData": mBaseData,
"String": []byte("abcd"),
"SliceByte": []string{"123", "456", "789"},
"SliceAny": []any{"123", "456", "789"},
"SliceStruct": []map[string]any{
{"Bool": true,
"Int8": int8(-1),
"Int16": int16(-2),
"Int32": int32(-3),
"Int64": int64(-4),
"UInt8": uint8(1),
"UInt16": uint16(2),
"UInt32": uint32(3),
"UInt64": uint64(4),
"Float32": float32(1.99),
"Float64": float64(2.9999),
},
},
"SliceSlice": [][]any{
{1, 23, 4},
{2, 4, 5},
},
"SliceMap": []map[string]any{
{
"1": 1,
"2": 2,
},
{
"11": 11,
"22": 22,
},
},
"Map": map[string]int{
"1": 1,
"2": 2,
},
"MapAny": map[string]any{
"1": 1,
"2": 2,
},
"MapStruct": map[string]any{
"BaseData": map[string]any{
"Bool": true,
"Int8": int8(-1),
"Int16": int16(-2),
"Int32": int32(-3),
"Int64": int64(-4),
"UInt8": uint8(1),
"UInt16": uint16(2),
"UInt32": uint32(3),
"UInt64": uint64(4),
"Float32": float32(1.99),
"Float64": float64(2.9999),
},
},
"MapMap": map[string]any{
"BaseData": map[string]any{
"Int32": int32(-3),
"UInt32": int32(3),
},
"BaseData1": map[string]any{
"Int32": int32(-4),
"UInt32": int32(4),
},
},
"MapSlice": map[string][]string{
"1": {"11", "22", "33"},
"2": {"2", "22", "33"},
},
}
ms := map[string]interface{}{
"MiddleData": mm,
}
//var st *StructData //这种不行,st==nil
// st := new(StructData) //一级指针
//sst := new(StructData) //二级指针
//st := &sst
//Int64 := int64(0)
//IInt64 := &Int64
//
//Float32 := float32(0.0)
//FFloat32 := &Float32
//
//bd := new(BaseData)
//bd.Int64 = &IInt64
//bd.Float32 = &FFloat32
//bbd := &bd
//
//md := new(MiddleData)
//md.RealBaseData = bbd
//
//mmd := &md
ssst := new(StructData) //三级指针
//ssst.RealBaseData = *bd
//ssst.RealMiddleData = mmd
sst := &ssst
st := &sst
MarshalStruct(ms, st)
//fmt.Println(bd)
fmt.Println("1")
}
上面的是自己随手写的一个map->struct的demo,可能存在一些细节上的bug,但是上面的例子是可以运行的,写这个的目的是为了熟悉反射的用法,所以你在上面能看到各种方法,是不一样的。
1.struct的fileld出来多级指针是可以canset的,因为直接给它赋值为flagsddr的,一般类型的多级指针是不行的
2.any通过通过类型中断出具体的类型,才可能通过反射得出它的具体类型,否则就是any类型
3.type的elem()的函数和value的函数elem的区别,是type的elem的函数,如果它是指针,指向的是指针指向的type,和value的差不多,如果是map和slice,是指向它元素的type,而value的elem只能有any和ptr的类型的值,any会怎么产生了,reflect.TypeOf((*BaseDataName)(nil)).Elem()
4.对于***的多级指针,如果不想一个一个的new,就应该反射,一个一个的new,然后赋值
2.rpc的函数的序列化
对于进程间的rpc函数我们一般是通过一个probuf的struct将所有的参数包裹起来成一个,但是我们可不可以传递多个参数了,答案是可以的,下面的代码是一个很简易的多个参数的写法,就是利用反射,记录函数类型的输入输出参数的类型,然后进行正反序列化
//probuf的结构体
type Ipacket struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Stx int32 `protobuf:"varint,1,opt,name=Stx,proto3" json:"Stx,omitempty"`
DestServerType SERVICE `protobuf:"varint,2,opt,name=DestServerType,proto3,enum=message.SERVICE" json:"DestServerType,omitempty"`
Ckx int32 `protobuf:"varint,3,opt,name=Ckx,proto3" json:"Ckx,omitempty"`
Id int64 `protobuf:"varint,4,opt,name=Id,proto3" json:"Id,omitempty"`
}
type C_A_LoginRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PacketHead *Ipacket `protobuf:"bytes,1,opt,name=PacketHead,proto3" json:"PacketHead,omitempty"`
AccountName string `protobuf:"bytes,2,opt,name=AccountName,proto3" json:"AccountName,omitempty"`
Password string `protobuf:"bytes,3,opt,name=Password,proto3" json:"Password,omitempty"`
BuildNo string `protobuf:"bytes,5,opt,name=BuildNo,proto3" json:"BuildNo,omitempty"`
Key int64 `protobuf:"varint,6,opt,name=Key,proto3" json:"Key,omitempty"` //uint32 Crc = 7;
}
func RegisterFunc(ctx context.Context, a int, pst *User, packet *message.C_A_LoginRequest) {
V := ctx.Value("funcname")
fmt.Println("ctx:", V)
fmt.Println("a:", a)
fmt.Println("pst:", pst)
fmt.Println("packet:", packet)
}
func SendFuncParams(b string, a int, pst *User, packet *message.C_A_LoginRequest) []byte {
return MashalCesi(b, a, pst, packet)
}
func MashalCesi(funcname string, p ...interface{}) []byte {
buffer := bytes.NewBuffer([]byte{})
enData := gob.NewEncoder(buffer)
enData.Encode(funcname)
for _, v := range p {
enData.Encode(v)
}
return buffer.Bytes()
}
func TestReflectRegisterFunc(t *testing.T) {
defer func() {
if err := recover(); err != nil {
fmt.Printf("=%s", err)
}
}()
funcname := "RegisterFunc"
funcType := reflect.TypeOf(RegisterFunc)
funcVal := reflect.ValueOf(RegisterFunc)
funcParams := reflect.TypeOf(RegisterFunc).String()
fmt.Println("funcParams is ", funcParams)
paramsNum := funcType.NumIn()
paramsNums := make([]interface{}, paramsNum)
user := &User{1, "Allen.Wu", 25}
packet1 := &message.C_A_LoginRequest{PacketHead: message.BuildPacketHead(0, message.SERVICE_GATESERVER),
AccountName: "lw", Password: "123456", BuildNo: "2", Key: 678}
buffer := SendFuncParams(funcname, 1, user, packet1)
buf := bytes.NewBuffer(buffer)
deData := gob.NewDecoder(buf)
for i := 0; i < paramsNum; i++ {
if i == 0 {
//val:=reflect.New(funcType.In(i)) //context.Context is not string
val := reflect.New(reflect.TypeOf(string("")))
deData.DecodeValue(val)
//name:=val.Interface().(string) //interface {} is *string, not string
name := val.Elem().Interface().(string)
paramsNums[i] = context.WithValue(context.Background(), "funcname", name)
continue
}
val := reflect.New(funcType.In(i))
deData.DecodeValue(val)
paramsNums[i] = val.Elem().Interface()
}
in := make([]reflect.Value, paramsNum)
for i := 0; i < paramsNum; i++ {
in[i] = reflect.ValueOf(paramsNums[i])
fmt.Println("funcParams is ", in[i])
}
funcVal.Call(in)
}
上面的代码可能不规范,但是目的是学习,没有用到mock的测试方法,
由于测试,我们省略了socket的网络传输,毕竟只要是[]byte就可以传输了,通过上面的方法我们就可以实现自己的多参数的rpc传输了。其实做游戏的,可以实现自己的SendRpc(SrcActorID,DstActorID,FuncName,...params)rpc函数的这种形式,这都是题外话了。
总结:反射还是很重要的知识,务必要好好掌握,最后,本人能力有限,希望大佬们多多提意见