反射介绍

  反射就是在运行期间(不是编译期间)探知对象的类型信息和内存结构、更新变量、调用它们的方法。
  反射的使用场景:

  • 函数的参数类型是interface{},需要在运行时对原始类型进行判断,针对不同的类型采取不同的处理方式。比如json.Marshal(v interface{})。
  • 在运行时根据某些条件动态决定调用哪个函数,比如根据配置文件执行相应的算子函数。

  Go标准库里的json序列化就使用了反射。

1
2
3
4
5
6
7
8
9
10
11
type User struct {
Name string
Age int
Sex byte `json:"gender"`
}
user := User{
Name: "钱钟书",
Age: 57,
Sex: 1,
}
json.Marshal(user) //返回 {"Name":"钱钟书","Age":57,"gender":1}

  反射的弊端:

  • 代码难以阅读,难以维护。
  • 编译期间不能发现类型错误,覆盖测试难度很大,有些bug需要到线上运行很长时间才能发现,可能会造成严重用后果。
  • 反射性能很差,通常比正常代码慢一到两个数量级。在对性能要求很高,或大量反复调用的代码块里建议不要使用反射。

反射的基础数据类型

  reflect.Type用于获取类型相关的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type Type interface {
Method(int) Method //第i个方法
MethodByName(string) (Method, bool) //根据名称获取方法
NumMethod() int //方法的个数
Name() string //获取结构体名称
PkgPath() string //包路径
Size() uintptr //占用内存的大小
String() string //获取字符串表述
Kind() Kind //数据类型
Implements(u Type) bool //判断是否实现了某接口
AssignableTo(u Type) bool //能否赋给另外一种类型
ConvertibleTo(u Type) bool //能否转换为另外一种类型
Elem() Type //解析指针
Field(i int) StructField //第i个成员
FieldByIndex(index []int) StructField //根据index路径获取嵌套成员
FieldByName(name string) (StructField, bool) //根据名称获取成员
FieldByNameFunc(match func(string) bool) (StructField, bool) //
Len() int //容器的长度
NumIn() int //输出参数的个数
NumOut() int //返回参数的个数
}

  通过reflect.Value获取、修改原始数据类型里的值。

1
2
3
4
5
6
type Value struct {
// 代表的数据类型
typ *rtype
// 指向原始数据的指针
ptr unsafe.Pointer
}

反射API

reflect.Type

如何得到Type

通过TypeOf()得到Type类型。

1
2
3
4
5
6
7
8
9
typeI := reflect.TypeOf(1)       
typeS := reflect.TypeOf("hello")
fmt.Println(typeI) //int
fmt.Println(typeS) //string

typeUser := reflect.TypeOf(&common.User{})
fmt.Println(typeUser) //*common.User
fmt.Println(typeUser.Kind()) //ptr
fmt.Println(typeUser.Elem().Kind()) //struct

指针Type转为非指针Type

1
2
3
typeUser := reflect.TypeOf(&common.User{}) 
typeUser2 := reflect.TypeOf(common.User{})
assert.IsEqual(typeUser.Elem(), typeUser2)

获取struct成员变量的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typeUser := reflect.TypeOf(common.User{}) //需要用struct的Type,不能用指针的Type
fieldNum := typeUser.NumField() //成员变量的个数
for i := 0; i < fieldNum; i++ {
field := typeUser.Field(i)
fmt.Printf("%d %s offset %d anonymous %t type %s exported %t json tag %s\n", i,
field.Name, //变量名称
field.Offset, //相对于结构体首地址的内存偏移量,string类型会占据16个字节
field.Anonymous, //是否为匿名成员
field.Type, //数据类型,reflect.Type类型
field.IsExported(), //包外是否可见(即是否以大写字母开头)
field.Tag.Get("json")) //获取成员变量后面``里面定义的tag
}
fmt.Println()

//可以通过FieldByName获取Field
if nameField, ok := typeUser.FieldByName("Name"); ok {
fmt.Printf("Name is exported %t\n", nameField.IsExported())
}
//也可以根据FieldByIndex获取Field
thirdField := typeUser.FieldByIndex([]int{2}) //参数是个slice,因为有struct嵌套的情况
fmt.Printf("third field name %s\n", thirdField.Name)

获取struct成员方法的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typeUser := reflect.TypeOf(common.User{})
methodNum := typeUser.NumMethod() //成员方法的个数。接收者为指针的方法【不】包含在内
for i := 0; i < methodNum; i++ {
method := typeUser.Method(i)
fmt.Printf("method name:%s ,type:%s, exported:%t\n", method.Name, method.Type, method.IsExported())
}
fmt.Println()

typeUser2 := reflect.TypeOf(&common.User{})
methodNum = typeUser2.NumMethod() //成员方法的个数。接收者为指针或值的方法【都】包含在内,也就是说值实现的方法指针也实现了(反之不成立)
for i := 0; i < methodNum; i++ {
method := typeUser2.Method(i)
fmt.Printf("method name:%s ,type:%s, exported:%t\n", method.Name, method.Type, method.IsExported())
}

获取函数的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func Add(a, b int) int {
return a + b
}

typeFunc := reflect.TypeOf(Add) //获取函数类型
fmt.Printf("is function type %t\n", typeFunc.Kind() == reflect.Func)
argInNum := typeFunc.NumIn() //输入参数的个数
argOutNum := typeFunc.NumOut() //输出参数的个数
for i := 0; i < argInNum; i++ {
argTyp := typeFunc.In(i)
fmt.Printf("第%d个输入参数的类型%s\n", i, argTyp)
}
for i := 0; i < argOutNum; i++ {
argTyp := typeFunc.Out(i)
fmt.Printf("第%d个输出参数的类型%s\n", i, argTyp)
}

判断类型是否实现了某接口

1
2
3
4
5
6
7
//通过reflect.TypeOf((*<interface>)(nil)).Elem()获得接口类型。因为People是个接口不能创建实例,所以把nil强制转为*common.People类型
typeOfPeople := reflect.TypeOf((*common.People)(nil)).Elem()
fmt.Printf("typeOfPeople kind is interface %t\n", typeOfPeople.Kind() == reflect.Interface)
t1 := reflect.TypeOf(common.User{})
t2 := reflect.TypeOf(&common.User{})
//如果值类型实现了接口,则指针类型也实现了接口;反之不成立
fmt.Printf("t1 implements People interface %t\n", t1.Implements(typeOfPeople))

reflect.Value

如果获得Value

通过ValueOf()得到Value。

1
2
3
4
5
6
7
8
9
10
11
iValue := reflect.ValueOf(1)
sValue := reflect.ValueOf("hello")
userPtrValue := reflect.ValueOf(&common.User{
Id: 7,
Name: "杰克逊",
Weight: 65,
Height: 1.68,
})
fmt.Println(iValue) //1
fmt.Println(sValue) //hello
fmt.Println(userPtrValue) //&{7 杰克逊 65 1.68}

Value转为Type

1
2
3
4
5
6
7
iType := iValue.Type()
sType := sValue.Type()
userType := userPtrValue.Type()
//在Type和相应Value上调用Kind()结果一样的
fmt.Println(iType.Kind() == reflect.Int, iValue.Kind() == reflect.Int, iType.Kind() == iValue.Kind())
fmt.Println(sType.Kind() == reflect.String, sValue.Kind() == reflect.String, sType.Kind() == sValue.Kind())
fmt.Println(userType.Kind() == reflect.Ptr, userPtrValue.Kind() == reflect.Ptr, userType.Kind() == userPtrValue.Kind())

指针Value和非指针Value互相转换

1
2
3
4
userValue := userPtrValue.Elem()                    //Elem() 指针Value转为非指针Value
fmt.Println(userValue.Kind(), userPtrValue.Kind()) //struct ptr
userPtrValue3 := userValue.Addr() //Addr() 非指针Value转为指针Value
fmt.Println(userValue.Kind(), userPtrValue3.Kind()) //struct ptr

得到Value对应的原始数据

通过Interface()函数把Value转为interface{},再从interface{}强制类型转换,转为原始数据类型。或者在Value上直接调用Int()、String()等一步到位。

1
2
3
4
5
6
fmt.Printf("origin value iValue is %d %d\n", iValue.Interface().(int), iValue.Int())
fmt.Printf("origin value sValue is %s %s\n", sValue.Interface().(string), sValue.String())
user := userValue.Interface().(common.User)
fmt.Printf("id=%d name=%s weight=%.2f height=%.2f\n", user.Id, user.Name, user.Weight, user.Height)
user2 := userPtrValue.Interface().(*common.User)
fmt.Printf("id=%d name=%s weight=%.2f height=%.2f\n", user2.Id, user2.Name, user2.Weight, user2.Height)

空Value的判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var i interface{} //接口没有指向具体的值
v := reflect.ValueOf(i)
fmt.Printf("v持有值 %t, type of v is Invalid %t\n", v.IsValid(), v.Kind() == reflect.Invalid)

var user *common.User = nil
v = reflect.ValueOf(user) //Value指向一个nil
if v.IsValid() {
fmt.Printf("v持有的值是nil %t\n", v.IsNil()) //调用IsNil()前先确保IsValid(),否则会panic
}

var u common.User //只声明,里面的值都是0值
v = reflect.ValueOf(u)
if v.IsValid() {
fmt.Printf("v持有的值是对应类型的0值 %t\n", v.IsZero()) //调用IsZero()前先确保IsValid(),否则会panic
}

通过Value修改原始数据的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var i int = 10
var s string = "hello"
user := common.User{
Id: 7,
Name: "杰克逊",
Weight: 65.5,
Height: 1.68,
}

valueI := reflect.ValueOf(&i) //由于go语言所有函数传的都是值,所以要想修改原来的值就需要传指针
valueS := reflect.ValueOf(&s)
valueUser := reflect.ValueOf(&user)
valueI.Elem().SetInt(8) //由于valueI对应的原始对象是指针,通过Elem()返回指针指向的对象
valueS.Elem().SetString("golang")
valueUser.Elem().FieldByName("Weight").SetFloat(68.0) //FieldByName()通过Name返回类的成员变量

强调一下,要想修改原始数据的值,给ValueOf传的必须是指针,而指针Value不能调用Set和FieldByName方法,所以得先通过Elem()转为非指针Value。
未导出成员的值不能通过反射进行修改。

1
2
3
4
5
6
addrValue := valueUser.Elem().FieldByName("addr")
if addrValue.CanSet() {
addrValue.SetString("北京")
} else {
fmt.Println("addr是未导出成员,不可Set") //以小写字母开头的成员相当于是私有成员
}

通过Value修改Slice

1
2
3
4
5
6
7
8
9
10
11
12
13
users := make([]*common.User, 1, 5) //len=1,cap=5
users[0] = &common.User{
Id: 7,
Name: "杰克逊",
Weight: 65.5,
Height: 1.68,
}

sliceValue := reflect.ValueOf(&users) //准备通过Value修改users,所以传users的地址
if sliceValue.Elem().Len() > 0 { //取得slice的长度
sliceValue.Elem().Index(0).Elem().FieldByName("Name").SetString("令狐一刀")
fmt.Printf("1st user name change to %s\n", users[0].Name)
}

甚至可以修改slice的cap,新的cap必须位于原始的len到cap之间,即只能把cap改小。

1
sliceValue.Elem().SetCap(3)

通过把len改大,可以实现向slice中追加元素的功能。

1
2
3
4
5
6
7
8
9
sliceValue.Elem().SetLen(2)
//调用reflect.Value的Set()函数修改其底层指向的原始数据
sliceValue.Elem().Index(1).Set(reflect.ValueOf(&common.User{
Id: 8,
Name: "李达",
Weight: 80,
Height: 180,
}))
fmt.Printf("2nd user name %s\n", users[1].Name)

修改map

Value.SetMapIndex()函数:往map里添加一个key-value对。
Value.MapIndex()函数: 根据Key取出对应的map。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
u1 := &common.User{
Id: 7,
Name: "杰克逊",
Weight: 65.5,
Height: 1.68,
}
u2 := &common.User{
Id: 8,
Name: "杰克逊",
Weight: 65.5,
Height: 1.68,
}
userMap := make(map[int]*common.User, 5)
userMap[u1.Id] = u1

mapValue := reflect.ValueOf(&userMap) //准备通过Value修改userMap,所以传userMap的地址
mapValue.Elem().SetMapIndex(reflect.ValueOf(u2.Id), reflect.ValueOf(u2)) //SetMapIndex 往map里添加一个key-value对
mapValue.Elem().MapIndex(reflect.ValueOf(u1.Id)).Elem().FieldByName("Name").SetString("令狐一刀") //MapIndex 根据Key取出对应的map
for k, user := range userMap {
fmt.Printf("key %d name %s\n", k, user.Name)
}

调用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
valueFunc := reflect.ValueOf(Add) //函数也是一种数据类型
typeFunc := reflect.TypeOf(Add)
argNum := typeFunc.NumIn() //函数输入参数的个数
args := make([]reflect.Value, argNum) //准备函数的输入参数
for i := 0; i < argNum; i++ {
if typeFunc.In(i).Kind() == reflect.Int {
args[i] = reflect.ValueOf(3) //给每一个参数都赋3
}
}
sumValue := valueFunc.Call(args) //返回[]reflect.Value,因为go语言的函数返回可能是一个列表
if typeFunc.Out(0).Kind() == reflect.Int {
sum := sumValue[0].Interface().(int) //从Value转为原始数据类型
fmt.Printf("sum=%d\n", sum)
}

调用成员方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
common.User{
Id: 7,
Name: "杰克逊",
Weight: 65.5,
Height: 1.68,
}
valueUser := reflect.ValueOf(&user) //必须传指针,因为BMI()在定义的时候它是指针的方法
bmiMethod := valueUser.MethodByName("BMI") //MethodByName()通过Name返回类的成员变量
resultValue := bmiMethod.Call([]reflect.Value{}) //无参数时传一个空的切片
result := resultValue[0].Interface().(float32)
fmt.Printf("bmi=%.2f\n", result)

//Think()在定义的时候用的不是指针,valueUser可以用指针也可以不用指针
thinkMethod := valueUser.MethodByName("Think")
thinkMethod.Call([]reflect.Value{})

valueUser2 := reflect.ValueOf(user)
thinkMethod = valueUser2.MethodByName("Think")
thinkMethod.Call([]reflect.Value{})

创建对象

创建struct

1
2
3
4
user :=t := reflect.TypeOf(common.User{})
value := reflect.New(t) //根据reflect.Type创建一个对象,得到该对象的指针,再根据指针提到reflect.Value
value.Elem().FieldByName("Id").SetInt(10)
user := value.Interface().(*common.User) //把反射类型转成go原始数据类型Call([]reflect.Value{})

创建slice

1
2
3
4
5
6
7
8
9
10
11
var slice []common.User
sliceType := reflect.TypeOf(slice)
sliceValue := reflect.MakeSlice(sliceType, 1, 3)
sliceValue.Index(0).Set(reflect.ValueOf(common.User{
Id: 8,
Name: "李达",
Weight: 80,
Height: 180,
}))
users := sliceValue.Interface().([]common.User)
fmt.Printf("1st user name %s\n", users[0].Name)

创建map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var userMap map[int]*common.User
mapType := reflect.TypeOf(userMap)
// mapValue:=reflect.MakeMap(mapType)
mapValue := reflect.MakeMapWithSize(mapType, 10)

user := &common.User{
Id: 7,
Name: "杰克逊",
Weight: 65.5,
Height: 1.68,
}
key := reflect.ValueOf(user.Id)
mapValue.SetMapIndex(key, reflect.ValueOf(user)) //SetMapIndex 往map里添加一个key-value对
mapValue.MapIndex(key).Elem().FieldByName("Name").SetString("令狐一刀") //MapIndex 根据Key取出对应的map
userMap = mapValue.Interface().(map[int]*common.User)
fmt.Printf("user name %s %s\n", userMap[7].Name, user.Name)

reflect包里除了MakeSlice()和MakeMap(),还有MakeChan()和MakeFunc()。

自行实现json序列化

  所谓序列化即把struct实例转为string。比如定义了User和Book两个struct。

1
2
3
4
5
6
7
8
9
10
type User struct {
Name string
Age int
Sex byte `json:"gender"`
}
type Book struct {
ISBN string `json:"isbn"`
Author User `json:"author"`
Keywords []string `json:"kws"`
}

  Book的实例序列化后为

1
2
3
4
5
6
7
8
9
{
"isbn": "4243547567",
"author": {
"Name": "钱钟书",
"Age": 57,
"gender": 1
},
"kws": ["爱情", "民国", "留学"]
}

  序列化实现思路:

  • 从内向外、从简单到复杂地考虑序列化问题。
    1. 如果要序列化一个int、float、string,很简单。
    2. 如果要序列化一个slice,则在第1步的基础上用[]括起来。
    3. 如果要序列化一个struct,FieldName直接打印出来,FieldValue的序列化可以参考第1、2步。
    4. 如果struct内部还嵌套了struct,则递归调用第3步。
  • 通过反射解析struct,得到json key和struct FieldName的对应关系。
  • 如果FieldValue是基本的值类型,则通过反射给FieldValue赋值很简单。
  • 如果FieldValue是slice类型,则需要通过反射先创建一个slice,再给slice里的每个元素赋值。
  • 如果FieldValue是是内嵌struct,则递归调用反序列化函数,给FieldValue赋值。
  • 如果FieldValue是是内嵌struct指针,则需要创建内嵌struct对应的实例(申请内存空间),再递归调用反序列化函数,给FieldValue赋值。

案例

序列化json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package main

import (
"bytes"
"fmt"
"reflect"
)

type User struct {
Name string
Age int
Sex byte `json:"gender"`
}

type Book struct {
ISBN string `json:"isbn"`
Name string
Price float32 `json:"price"`
Author *User `json:"author"` //把指针去掉试试
Keywords []string `json:"kws"`
Local map[int]bool //暂不支持map
}

func Marshal(v interface{}) ([]byte, error) {
value := reflect.ValueOf(v)
typ := value.Type() //跟typ := reflect.TypeOf(v)等价
if typ.Kind() == reflect.Ptr {
if value.IsNil() { //如果指向nil,直接输出null
return []byte("null"), nil
} else { //如果传的是指针类型,先解析指针
typ = typ.Elem()
value = value.Elem()
}
}
bf := bytes.Buffer{} //存放序列化结果
switch typ.Kind() {
case reflect.String:
return []byte(fmt.Sprintf("\"%s\"", value.String())), nil //取得reflect.Value对应的原始数据的值
case reflect.Bool:
return []byte(fmt.Sprintf("%t", value.Bool())), nil
case reflect.Float32,
reflect.Float64:
return []byte(fmt.Sprintf("%f", value.Float())), nil
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64,
reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
return []byte(fmt.Sprintf("%v", value.Interface())), nil
case reflect.Slice:
if value.IsValid() && value.IsNil() {
return []byte("null"), nil
}
bf.WriteByte('[')
if value.Len() > 0 {
for i := 0; i < value.Len(); i++ { //取得slice的长度
if bs, err := Marshal(value.Index(i).Interface()); err != nil { //对slice的第i个元素进行序列化。递归
return nil, err
} else {
bf.Write(bs)
bf.WriteByte(',')
}
}
bf.Truncate(len(bf.Bytes()) - 1) //删除最后一个逗号
}
bf.WriteByte(']')
return bf.Bytes(), nil
case reflect.Map:
if value.IsValid() && value.IsNil() {
return []byte("null"), nil
}
bf.WriteByte('{')
if value.Len() > 0 {
for _, key := range value.MapKeys() {
if keyBs, err := Marshal(key.Interface()); err != nil {
return nil, err
} else {
bf.WriteByte('"')
bf.Write(keyBs)
bf.WriteByte('"')
bf.WriteByte(':')
v := value.MapIndex(key)
if vBs, err := Marshal(v.Interface()); err != nil {
return nil, err
} else {
bf.Write(vBs)
bf.WriteByte(',')
}
}
}
bf.Truncate(len(bf.Bytes()) - 1) //删除最后一个逗号
}
bf.WriteByte('}')
return bf.Bytes(), nil
case reflect.Struct:
bf.WriteByte('{')
if value.NumField() > 0 {
for i := 0; i < value.NumField(); i++ {
fieldValue := value.Field(i)
fieldType := typ.Field(i)
if fieldType.IsExported() {
name := fieldType.Name //如果没有json Tag,默认使用成员变量的名称
if len(fieldType.Tag.Get("json")) > 0 {
name = fieldType.Tag.Get("json")
}
bf.WriteString("\"")
bf.WriteString(name)
bf.WriteString("\"")
bf.WriteString(":")
if bs, err := Marshal(fieldValue.Interface()); err != nil { //对value递归调用Marshal序列化
return nil, err
} else {
bf.Write(bs)
}
bf.WriteString(",")
}
}
bf.Truncate(len(bf.Bytes()) - 1) //删除最后一个逗号
}
bf.WriteByte('}')
return bf.Bytes(), nil
default:
return []byte(fmt.Sprintf("\"暂不支持该数据类型:%s\"", typ.Kind().String())), nil
}
}

func main() {
book := Book{
ISBN: "4243547567",
Name: "围城",
Price: 34.8,
Author: &User{Name: "钱钟书", Age: 55, Sex: 1}, //改成nil试试
Keywords: []string{"爱情", "民国", "留学"}, //把这一行注释掉试一下,测测null
Local: map[int]bool{2: true, 3: false},
}
if b, err := Marshal(book); err != nil {
fmt.Printf("序列化失败: %v\n", err)
} else {
fmt.Println(string(b))
}
}

运行结果:
{“isbn”:“4243547567”,“Name”:“围城”,“price”:34.799999,“author”:{“Name”:“钱钟书”,“Age”:55,“gender”:1},“kws”:[“爱情”,“民国”,“留学”],“Local”:{“2”:true,“3”:false}}

反序列化json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package main

import (
"container/list"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
)

type User struct {
Name string
Age int
Sex byte `json:"gender"`
}

type Book struct {
ISBN string `json:"isbn"`
Name string
Price float32 `json:"price"`
Author *User `json:"author"` //把指针去掉试试
Keywords []string `json:"kws"`
Local map[int]bool //暂不支持map
}

// 由于json字符串里存在{}[]等嵌套情况,直接按,分隔是不合适的
func SplitJson(json string) []string {
rect := make([]string, 0, 10)
stack := list.New() //list是双端队列,用它来模拟栈
beginIndex := 0
for i, r := range json {
if r == rune('{') || r == rune('[') {
stack.PushBack(struct{}{}) //我们不关心栈里是什么,只关心栈里有没有元素
} else if r == rune('}') || r == rune(']') {
ele := stack.Back()
if ele != nil {
stack.Remove(ele) //删除栈顶元素
}
} else if r == rune(',') {
if stack.Len() == 0 { //栈为空时才可以按,分隔
rect = append(rect, json[beginIndex:i])
beginIndex = i + 1
}
}
}
rect = append(rect, json[beginIndex:])
return rect
}

func Unmarshal(data []byte, v interface{}) error {
s := string(data)
//去除前后的连续空格
s = strings.TrimLeft(s, " ")
s = strings.TrimRight(s, " ")
if len(s) == 0 {
return nil
}
typ := reflect.TypeOf(v)
value := reflect.ValueOf(v)
if typ.Kind() != reflect.Ptr { //因为要修改v,必须传指针
return errors.New("must pass pointer parameter")
}

typ = typ.Elem() //解析指针
value = value.Elem()

switch typ.Kind() {
case reflect.String:
if s[0] == '"' && s[len(s)-1] == '"' {
value.SetString(s[1 : len(s)-1]) //去除前后的""
} else {
// return errors.New(fmt.Sprintf("invalid json part: %s", s))
return fmt.Errorf("invalid json part: %s", s)
}
case reflect.Bool:
if b, err := strconv.ParseBool(s); err == nil {
value.SetBool(b)
} else {
return err
}
case reflect.Float32,
reflect.Float64:
if f, err := strconv.ParseFloat(s, 64); err != nil {
return err
} else {
value.SetFloat(f) //通过reflect.Value修改原始数据的值
}
case reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
if i, err := strconv.ParseInt(s, 10, 64); err != nil {
return err
} else {
value.SetInt(i) //有符号整型通过SetInt
}
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
if i, err := strconv.ParseUint(s, 10, 64); err != nil {
return err
} else {
value.SetUint(i) //无符号整型需要通过SetUint
}
case reflect.Slice:
if s[0] == '[' && s[len(s)-1] == ']' {
arr := SplitJson(s[1 : len(s)-1]) //去除前后的[]
if len(arr) > 0 {
slice := reflect.ValueOf(v).Elem() //别忘了,v是指针
slice.Set(reflect.MakeSlice(typ, len(arr), len(arr))) //通过反射创建slice
for i := 0; i < len(arr); i++ {
eleValue := slice.Index(i)
eleType := eleValue.Type()
if eleType.Kind() != reflect.Ptr {
eleValue = eleValue.Addr() //Elem
}
if err := Unmarshal([]byte(arr[i]), eleValue.Interface()); err != nil {
return err
}
}
}
} else if s != "null" {
return fmt.Errorf("invalid json part: %s", s)
}
case reflect.Map:
if s[0] == '{' && s[len(s)-1] == '}' {
arr := SplitJson(s[1 : len(s)-1]) //去除前后的{}
if len(arr) > 0 {
mapValue := reflect.ValueOf(v).Elem() //别忘了,v是指针
mapValue.Set(reflect.MakeMapWithSize(typ, len(arr))) //通过反射创建map

kType := typ.Key() //获取map的key的Type
vType := typ.Elem() //获取map的value的Type
for i := 0; i < len(arr); i++ {
brr := strings.Split(arr[i], ":")
if len(brr) != 2 {
return fmt.Errorf("invalid json part: %s", arr[i])
}

kValue := reflect.New(kType) //根据Type创建指针型的Value
if err := Unmarshal([]byte(brr[0]), kValue.Interface()); err != nil {
return err
}
vValue := reflect.New(vType) //根据Type创建指针型的Value
if err := Unmarshal([]byte(brr[1]), vValue.Interface()); err != nil {
return err
}
mapValue.SetMapIndex(kValue.Elem(), vValue.Elem()) //往map里面赋值
}
}
} else if s != "null" {
return fmt.Errorf("invalid json part: %s", s)
}
case reflect.Struct:
if s[0] == '{' && s[len(s)-1] == '}' {
arr := SplitJson(s[1 : len(s)-1])
if len(arr) > 0 {
fieldCount := typ.NumField()
//建立json tag到FieldName的映射关系
tag2Field := make(map[string]string, fieldCount)
for i := 0; i < fieldCount; i++ {
fieldType := typ.Field(i)
name := fieldType.Name
if len(fieldType.Tag.Get("json")) > 0 {
name = fieldType.Tag.Get("json")
}
tag2Field[name] = fieldType.Name
}

for _, ele := range arr {
brr := strings.SplitN(ele, ":", 2) //json的value里可能存在嵌套,所以用:分隔时限定个数为2
if len(brr) == 2 {
tag := strings.Trim(brr[0], " ")
if tag[0] == '"' && tag[len(tag)-1] == '"' { //json的key肯定是带""的
tag = tag[1 : len(tag)-1] //去除json key前后的""
if fieldName, exists := tag2Field[tag]; exists { //根据json key(即json tag)找到对应的FieldName
fieldValue := value.FieldByName(fieldName)
fieldType := fieldValue.Type()
if fieldType.Kind() != reflect.Ptr {
//如果内嵌不是指针,则声明时已经用0值初始化了,此处只需要根据json改写它的值
fieldValue = fieldValue.Addr() //确保fieldValue指向指针类型,因为接下来要把fieldValue传给Unmarshal
if err := Unmarshal([]byte(brr[1]), fieldValue.Interface()); err != nil { //递归调用Unmarshal,给fieldValue的底层数据赋值
return err
}
} else {
//如果内嵌的是指针,则需要通过New()创建一个实例(申请内存空间)。不能给New()传指针型的Type,所以调一下Elem()
newValue := reflect.New(fieldType.Elem()) //newValue代表的是指针
if err := Unmarshal([]byte(brr[1]), newValue.Interface()); err != nil { //递归调用Unmarshal,给fieldValue的底层数据赋值
return err
}
value.FieldByName(fieldName).Set(newValue) //把newValue赋给value的Field
}

} else {
fmt.Printf("字段%s找不到\n", tag)
}
} else {
return fmt.Errorf("invalid json part: %s", tag)
}
} else {
return fmt.Errorf("invalid json part: %s", ele)
}
}
}
} else if s != "null" {
return fmt.Errorf("invalid json part: %s", s)
}
default:
fmt.Printf("暂不支持类型:%s\n", typ.Kind().String())
}
return nil
}

func main() {
json_str := `{"isbn":"4243547567","Name":"围城","price":34.799999,"author":{"Name":"钱钟书","Age":55,"gender":1},"kws":["爱情","民国","留学"],"Local":{"2":true,"3":false}}`
var book Book //必须先声明值类型,再通过&给Unmarshal传一个指针参数。因为声明值类型会初始化为0值,而声明指针都没有创建底层的内存空间
if err := Unmarshal([]byte(json_str), &book); err != nil {
fmt.Printf("err: %v\n", err)
}
fmt.Printf("book: %+v\n", book)
}

运行结果:

book: {ISBN:4243547567 Name:围城 Price:34.8 Author:0xc000050440 Keywords:[爱情 民国 留学] Local:map[2:true 3:false]}