1,变量的介绍
1.变量的内在机制
- 1.类型信息:这部分是源信息,是预先定义好的
- 2.值信息:这部分是程序运行过程中,动态改变的
2.反射介绍
1.反射与空接口
- 1.空接口可以存储任何类型的变量
- 2.给你一个空接口,怎么知道里面存储的是什么东西
- 3.在运行时,动态获取一个变量的类型信息和值信息,就叫反射
2.反射的解析
1.内置包:reflect
2.获取类型信息:reflect.TypeOf
1.获取变量类型
package main
import (
"fmt"
"reflect"
)
func reflectExample(a interface{}) {
t := reflect.TypeOf(a) // 类型相关信息
k := t.Kind() // 获取具体类型
switch k {
case reflect.Int:
fmt.Println("a is int")
case reflect.Float64:
fmt.Println("a is float64")
case reflect.Array:
fmt.Println("a is array")
default:
fmt.Println("unknow type")
}
}
func main() {
x := 3.4
reflectExample(x)
}
3.获取值信息:reflect.ValueOf
1.获取变量类型
package main
import (
"fmt"
"reflect"
)
func reflectExample(a interface{}) {
v := reflect.ValueOf(a) // 类型相关信息
t := v.Type() // 和 reflect.TypeOf 一样
fmt.Println(t.Kind() == reflect.Float64)
}
func main() {
x := 3.4
reflectExample(x)
}
2.获取变量绑定的值
package main
import (
"fmt"
"reflect"
)
func reflectExample(a interface{}) {
v := reflect.ValueOf(a) // 类型相关信息
t := v.Kind() // 和 reflect.TypeOf 一样
switch t {
case reflect.Int:
value := v.Int()
fmt.Println("a is int store value is ", value)
case reflect.Float64:
value := v.Float() // 获取变量绑定的值
fmt.Println("a is int store value is ", value)
}
}
func main() {
x := 3.4
reflectExample(x)
}
3.设置变量的值
package main
import (
"fmt"
"reflect"
)
func reflectExample(a interface{}) {
v := reflect.ValueOf(a) // 类型相关信息
t := v.Kind() // 和 reflect.TypeOf 一样
switch t {
case reflect.Int:
value := v.Int()
fmt.Println("a is int store value is ", value)
case reflect.Float64:
v.SetFloat(7.8)
fmt.Println("set value success")
case reflect.Ptr: // 获取指针类型
v.Elem().SetFloat(6.8)
/*
var b *int = new(int)
*b = 20 // v.Elem()
*/
}
}
func main() {
x := 3.4
//reflectExample(x) // 会在16行报错,x是值类型,所以在函数内部是无法修改到函数外部的变量值的
reflectExample(&x)
fmt.Println(x) // 6.8
}
3.结构体反射
1.获取结构体信息
package main
import (
"fmt"
"reflect"
)
func reflectExample(a interface{}) {
v := reflect.ValueOf(a) // 类型相关信息
t := v.Type() // 和 reflect.TypeOf 一样
k := t.Kind()
switch k {
case reflect.Int:
fmt.Println("a is int")
case reflect.Struct:
fieldsNum := v.NumField() // 获取结构体元素个数(小写也可以统计到)
for i := 0; i < fieldsNum; i++ {
field := v.Field(i) // 根据下标获取字段信息(使用值对象获取)
fieldName := t.Field(i).Name // 获取字段名称(使用类型对象获取)
fieldType := field.Type().Kind() // 获取字段对应的类型
fieldValue := field.Interface() // 获取字段对应的值
/*
var fieldValue interface{}
switch fieldType { // 也可以通过fieldType类型获取
case reflect.Int:
intValue := field.Int()
fieldValue = intValue
case reflect.String:
strValue := field.String()
fieldValue = strValue
}
*/
fmt.Printf("%s: %s --> %v\n", fieldName, fieldType, fieldValue)
}
/*
Name: string - 小李
Sex: int - 1
Age: int - 22
*/
default:
fmt.Println("default type")
}
}
type Student struct {
Name string
Sex int
Age int
}
func main() {
s := Student{"小李", 1, 22,}
reflectExample(s)
}
v := reflect.ValueOf(a)
fieldsNum := v.NumField()
field := v.Field(i)
fieldType := field.Type().Kind():获取字段名对应的类型
fieldValue := field.Interface():获取字段名对应的值
t := reflect.TypeOf(a)
2.设置结构体信息
type Student struct {
Name string
Sex int
Age int
}
func main() {
s := Student{"小李", 1, 22,}
v := reflect.ValueOf(&s) // 类型相关信息
// v.Elem() ---> *v
v.Elem().Field(0).SetString("小张") // 通过索引设置字段值
v.Elem().FieldByName("Sex").SetInt(0) // 通过字段名设置值
v.Elem().FieldByName("Age").SetInt(18)
fmt.Println(s) // {小张 0 18}
}
3.获取结构体绑定的方法
package main
import (
"fmt"
"reflect"
)
func reflectExample(a interface{}) {
v := reflect.ValueOf(a)
t := v.Tpye()
k := t.Kind()
switch k {
case reflect.Int:
fmt.Println("a is int")
case reflect.Ptr: // 如果传递的是对象而不是引用,则需要在Struct中捕获
/*
可以根据指针获取到具体的对象,然后再判断具体对象的类型,从而实现精确赋值
obj := t.Elem()
switch obj.Kind() {
case reflect.Int:
v.Int(1)
case reflect.Struct:
fmt.Println("a is a struct")
}
*/
methodNum := t.NumMethod() // 获取结构体方法个数(小写也可以统计到)
// t.MethodByName("SetName") 通过方法名获取
for i := 0; i < methodNum; i++ {
method := t.Method(i) // 得到一个方法的结构体
/*
type Method struct {
Name string
PkgPath string
Type Type
Func Value
Index Int
}
*/
methodName := method.Name
methodType := method.Type // 获取方法的签名
fmt.Printf("%s: %v\n", methodName, methodType) // SetName: func(main.Student, string)
}
default:
fmt.Println("default type")
}
}
type Student struct {
Name string
Sex int
Age int
}
func (s *Student) SetName(name string) {
s.Name = name
}
func main() {
var s Student
reflectExample(&s)
}
4.调用结构体中的方法
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name string
Sex int
Age int
}
func (s *Student) SetName(name string) {
s.Name = name
}
func main() {
var s Student
v := reflect.ValueOf(&s)
method := v.MethodByName("SetName")
// 定义一个空切片
var args []reflect.Value
name := "小虎"
// 将字符串转换为reflect.Value类型
nameValue := reflect.ValueOf(name)
// 将reflect.Value类型的字符串添加到reflect.Value类型的切片中
args = append(args, nameValue)
// 调用SetName方法,传递参数
method.Call(args)
fmt.Println(s) // {小虎 0 0}
}
5.获取结构体中的tag信息
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name string `json:"name"`
Sex int
Age int
}
func main() {
var s Student
t := reflect.TypeOf(&s)
nameStruct, ok := t.Elem().FieldByName("Name") // 根据字段名获取字段对象
if ok {
fmt.Println(nameStruct.Name) // Name
fmt.Println(nameStruct.Tag.Get("json")) // name
}
// 也可以通过索引获取字段信息
field0 := t.Elem().Field(0)
fmt.Println(field0.Name) // Name
fmt.Println(field0.Tag.Get("json")) // name
}
4.反射总结级应用场景
1.总结
2.应用场景
- 1.序列化和反序列化,比如:
json、protobuf
- 2.各种非数据库的
ORM,比如:gorm、sqlx等中间件
- 3.配置文件解析相关的库,比如:
yaml、ini等