学习反射之前,先了解一下JSON
一、什么是JSON
1. 概述
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。key-val
JSON是在2001年开始推广使用的数据格式,目前已经成为主流的数据格式
JSON易于机器解析和生成,并有效地提升网络传输效率,通常程序在网络传输时会先将数据(结构体、map等)序列化成ison字符串,到接收方得到ison字符串时,在反序列化恢复成原来的数据类型(结构体、map等)。这种方式已然成为各个语言的标准。

2. 使用场景
比如:我们后端发送的数据,会序列化为json字符串到前端,那么前端怎么处理呢?
前端拿到json字符串,会进行反序列化json字符串为相应的数据!

3. json格式
在IS语言中,一切都是对象。因此,任何的数据类型都可以通过JSON来表示,例如字符串、数字、对象、数组,map,结构体等.
JSON 键值对是用来保存 数据一种方式,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号:分隔,然后紧接着值:
go
// 对象json格式
{"key1":"val1","key2":"val2"}
// 数组对象json格式
[{"key1":"val1","key2":"val2"},{"key1":"val1","key2":"val2"}]
二、JSON序列化
1. json序列化
json序列化是指,将有 key-value 结构的数据类型(比如结构体、map、切片)序列化成json 字符串的操作。
go
func TestJson(t *testing.T) {
p := Person{"Bob", 20}
marshal, _ := json.Marshal(p)
fmt.Println(string(marshal))
}
//=== RUN TestJson
//{"Name":"Bob","Age":20}
//--- PASS: TestJson (0.00s)
//PASS
2. json反序列化
实现了Unmarshaler接口的对象可以将自身的json描述反序列化。该方法可以认为输入是合法的json字符串。如果要在方法返回后保存自身的json数据,必须进行拷贝。
go
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
测试下反序列化
go
func TestUnmarshal(t *testing.T) {
jsonStr := `{"Name":"Bob","Age":20}`
p := Person{}
err := json.Unmarshal([]byte(jsonStr), &p)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Person=%v,Person.Name=%v\n", p, p.Name)
}
//=== RUN TestUnmarshal
//Person={Bob 20},Person.Name=Bob
//--- PASS: TestJson2 (0.00s)
//PASS
3. json属性标签
go语言的属性是通过首字母大小写,进行控制权限的,如何进行格式化变为小写,可以使用属性标签的写法,其实就是别名的意思。
go
type Person struct {
Name string `json:"name"`
Age int `json:"age,string"`
}
func TestJsonTag(t *testing.T) {
p := Person{"Bob", 20}
marshal, _ := json.Marshal(p)
fmt.Println(string(marshal))
}
//=== RUN TestJsonTag
//{"name":"Bob","age":"20"}
//--- PASS: TestJsonTag (0.00s)
//PASS
属性名称和类型进行了重新定义
三、反射
1. 反射基本介绍
- 反射可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind)
- 如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
- 通过反射,可以修改变量的值,可以调用关联的方法。
- 使用反射,需要 import("reflect")
2. 反射应用场景
1.不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。
go
func bridge(funPtr interface{}, args ..interface{})
第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数
2.对结构体序列化时,如果结构体有指定Tag,也会使用到反射生成对应的字符串。
go
type Person struct {
Name string `json:"name"`
Age int `json:"age,string"`
}
func TestJsonTag(t *testing.T) {
p := Person{"Bob", 20}
marshal, _ := json.Marshal(p)
fmt.Println(string(marshal))
}
3. 使用到的函数
- reflect.TypeOf(变量名): 获取变量的类型,返回reflect.Type类型
- reflect.ValueOf(变量名): 获取变量的值,返回reflect.Value类型reflect.Value 是一个结构体类型。
- 变量、interface[]和reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到。

4. 简单示例
1.通过反射获取变量的类型和值
go
package main
import (
"fmt"
"reflect"
)
func reflectTest01(b interface{}) {
// 获取变量的 reflect.Type
numType := reflect.TypeOf(b)
fmt.Println(numType)
// int
// 获取变量的 reflect.Value
numValue := reflect.ValueOf(b)
fmt.Println(numValue)
// 10
// 获取的变量值转换未interface{}
numInter := numValue.Interface()
// 将interface{}转换成具体类型
numInterType := numInter.(int)
fmt.Println(numInterType)
// 10
}
func main() {
var num int = 10
reflectTest01(num)
}
2.通过反射获取结构体类型和值
go
package main
import (
"fmt"
"reflect"
)
func reflectTest02(b interface{}) {
// 获取变量的 reflect.Type
monsterType := reflect.TypeOf(b)
fmt.Println(monsterType)
// main.Monster
// 获取变量的 reflect.Value
monsterValue := reflect.ValueOf(b)
fmt.Println(monsterValue)
// {xiaoming 10}
// 获取的变量值转换未interface{}
monsterInter := monsterValue.Interface()
// 将interface{}转换成具体类型
studentInterType := monsterInter.(Monster)
fmt.Println(studentInterType)
// {xiaoming 10}
}
type Monster struct {
Name string
Age int
}
func main() {
Monster := Monster{
Name: "xiaoming",
Age: 10,
}
reflectTest02(Monster)
}
附
本篇简单介绍了反射使用到的json格式,并介绍了反射使用到的方法
通过TypeOf获取变量和结构体的类型,通过ValueOf获取变量和结构体的值
本篇过于简单,说明了反射基本概念和简单入门,相关文档
goAPI文档:https://studygolang.com/pkgdoc
reflect包文档:https://studygolang.com/static/pkgdoc/pkg/reflect.htm