反射(reflect)功能是让我们能在运行期间获取对象的类型。
Type和Kind
可以定义类型的别名,类型是真实比对真实的基本类型。下面有一个例子代码可以看出二者的差别。
package main
import (
"fmt"
"reflect"
)
type X int // 取了一个别名
type Y int
func main() {
var a, b X = 100, 100
var c Y = 300
t := reflect.TypeOf(a)
fmt.Println(t.Name(), t.Kind())
ta, tb, tc := reflect.TypeOf(a), reflect.TypeOf(b), reflect.TypeOf(c)
fmt.Print(ta == tb, ta == tc) // true,false
fmt.Println(ta.Kind() == tc.Kind()) // true
}
结构体指针字段遍历
type user struct {
name string
age int
}
type manager struct {
user
title string
}
func tStruct() {
var m manager
t := reflect.TypeOf(m)
name, _ := t.FieldByName("name")
fmt.Println(name.Name, name.Type)
age := t.FieldByIndex([]int{0, 1}) // 第一级索引里面第二个元素
fmt.Println(age.Name, age.Type)
}
输出内容:
name string
age int
这里是通过名字去查询,或者通过多级索引去直接定位。
通过反射构造一些基础的数据结构
func tCreateBaseData() {
a := reflect.ArrayOf(10, reflect.TypeOf(byte(0)))
m := reflect.MapOf(reflect.TypeOf(""), reflect.TypeOf(0))
fmt.Println(a, m)
}
输出:
[10] uint8 map[string] int
struct tag
在反射的时候能读取修饰的信息,json解析的时候会读取这些数据。
type user struct {
name string `field:"name" type:"varchar(50)"`
age int `field:"age" type:"int"`
}
func tGetStructTag() {
var u user
t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Printf("%s: %s %s\n", f.Name, f.Tag.Get("field"), f.Tag.Get("type"))
}
}
name: name varchar(50)
age: age int
总结一下,反射部分其实由于执行的效率太低了,所以基本上使用的机会非常少。除了struct tag部分,可以为struct备注附加信息。