反射可以在運行時獲取對象的類型信息和內(nèi)存結構。反射操作所需的全部信息來自于接口變量,接口變量除存儲自身類型外,還會保存實際對象的類型信息。
func TypeOf(i interface{}) Type
func ValueOf(i interface{}) Value
類型
Name & Kind
Name獲取靜態(tài)類型,Kind獲取的是底層類型;在自定義類型的變量中獲取到的值是不一樣的。
type NewInt int
var x NewInt = 100
t := reflect.TypeOf(x)
fmt.Println(t, t.Name(), t.Kind()) // main.NewInt NewInt int
Kind支持的類型如下所示:
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
指針類型
傳入對象分區(qū)為基類型和指針類型,他們并不屬于同一類型。方法Elem返回指針、數(shù)組、切片、通道、字典(值)的基類型。
type NewInt int
var x NewInt = 100
tx, tp := reflect.TypeOf(x), reflect.TypeOf(&x)
fmt.Println(tx.Kind(), tp.Kind(), tx == tp, tx == tp.Elem()) // int ptr false true
不同基類型的指針也是不等的
var x rune = 100
var y uint32 = 100
tx, ty := reflect.TypeOf(&x), reflect.TypeOf(&y)
fmt.Println(tx.Kind(), ty.Kind(), tx == ty, tx.Elem() == ty.Elem()) // ptr ptr false false
結構體類型
只有在獲取結構體指針的基類型后才能對其遍歷
type user struct {
name string
age int
}
type manager struct {
user
title string
}
func main() {
m := &manager{user{"Jack", 18}, "boss"}
t := reflect.TypeOf(m)
if t.Kind() == reflect.Ptr { // 獲取指針的基類型
t = t.Elem()
}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Println(f.Type)
if f.Anonymous { // 輸出匿名字段信息(user)
for j := 0; j < f.Type.NumField(); j++ {
subf := f.Type.Field(j)
fmt.Println(subf.Type)
}
}
}
}
/*
main.user
string
int
string
*/
Field和NumField可以訪問當前包或者外包的非導出結構成員。
var s http.Server
t := reflect.TypeOf(s)
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Name)
}
// Addr,Handler,TLSConfig,ReadTimeout,ReadHeaderTimeout,WriteTimeout,IdleTimeout,MaxHeaderBytes,TLSNextProto,ConnState,ErrorLog,BaseContext,ConnContext,disableKeepAlives,inShutdown,nextProtoOnce,nextProtoErr,mu,listeners,activeConn,doneChan,onShutdown,
對于匿名字段,也可以通過FieldByName和FieldByIndex直接訪問
type user struct {
name string
age int
}
type manager struct {
user
title string
}
func main() {
m := manager{user{"Jack", 18}, "boss"}
t := reflect.TypeOf(m)
name, exists := t.FieldByName("name") // 多級訪問時無法訪問嵌套的同名字段
if exists {
fmt.Println(name.Type) // string
}
sex, exists := t.FieldByName("sex")
if exists {
fmt.Println(sex.Type)
}
age := t.FieldByIndex([]int{0, 1}) // 支持多級訪問
fmt.Println(age.Type)
}
輸出方法集(FIX)
struct tag
利用反射提取struct tag,常用于ORM映射或者數(shù)據(jù)格式驗證。
type user struct {
name string `field:"name" type:"varchar(50)"`
age int `field:"age" type:"int"`
}
func main() {
var u user
t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {
attr := t.Field(i)
fmt.Println(attr.Tag.Get("field"), attr.Tag.Get("type"))
}
}
// name varchar(50)
// age int