反射

反射可以在運行時獲取對象的類型信息和內(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
*/

FieldNumField可以訪問當前包或者外包的非導出結構成員。

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,

對于匿名字段,也可以通過FieldByNameFieldByIndex直接訪問

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
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容