go語言reflect包使用的幾個場景

李維發表於2019-02-16

reflect包的幾個使用場景:

1. 遍歷結構體欄位名(避免程式碼的硬編碼)
2. 呼叫結構體方法(自動對映)
3. 獲取結構體的tag標記的值(json/xml轉換)
4. // @todo更多的使用場景

程式碼:

一、$GOPATH/reflectusage/main.go:

// reflect使用場景
package main

import (
    "errors"
    "fmt"
    "reflect"
    "reflectusage/config"
)

func main() {

    // 建立Conf例項
    conf := config.Conf{}

    opName := "create"
    conf.Op = &opName
    conf.Port = 3308

    fmt.Printf("conf.Port=%d

", conf.Port)

    // 結構資訊
    t := reflect.TypeOf(conf)
    // 值資訊
    v := reflect.ValueOf(conf)

    printStructField(&t)

    callMethod(&v, "SayOp", []interface{}{" Db"})

    // panic: reflect: Call of unexported method
    //callMethod(&v, "getDbConf", []interface{}{})

    getTag(&t, "Op", "json")
    getTag(&t, "Op", "xml")
    getTag(&t, "nofield", "json")
}

// 場景1:遍歷結構體欄位名
func printStructField(t *reflect.Type) {
    fieldNum := (*t).NumField()
    for i := 0; i < fieldNum; i++ {
        fmt.Printf("conf`s field: %s
", (*t).Field(i).Name)
    }
    fmt.Println("")
}

// 場景2:呼叫結構體方法
func callMethod(v *reflect.Value, method string, params []interface{}) {
    // 字串方法呼叫,且能找到例項conf的屬性.Op
    f := (*v).MethodByName(method)
    if f.IsValid() {
        args := make([]reflect.Value, len(params))
        for k, param := range params {
            args[k] = reflect.ValueOf(param)
        }
        // 呼叫
        ret := f.Call(args)
        if ret[0].Kind() == reflect.String {
            fmt.Printf("%s Called result: %s
", method, ret[0].String())
        }
    } else {
        fmt.Println("can`t call " + method)
    }
    fmt.Println("")
}

// 場景3:獲取結構體的tag標記
func getTag(t *reflect.Type, field string, tagName string) {
    var (
        tagVal string
        err    error
    )
    fieldVal, ok := (*t).FieldByName(field)
    if ok {
        tagVal = fieldVal.Tag.Get(tagName)
    } else {
        err = errors.New("no field named:" + field)
    }

    fmt.Printf("get struct[%s] tag[%s]: %s, error:%v
", field, tagName, tagVal, err)
    fmt.Println("")
}

// @todo更多的使用場景

二、$GOPATH/reflectusage/config/config.go:

package config

type Db struct {
    Port int
    Host string
    pw   string
}

type Conf struct {
    Op       *string `json:"jsonop" xml:"xmlOpName"`
    Charlist *string
    Length   *int
    Num      *int
    Output   *string
    Input    *string
    hidden   *string
    Db
}

func (this Conf) SayOp(subname string) string {
    return *this.Op + subname
}

func (this Conf) getDbConf() Db {
    return this.Db
}

三、輸出:

conf.Port=3308

conf`s field: Op
conf`s field: Charlist
conf`s field: Length
conf`s field: Num
conf`s field: Output
conf`s field: Input
conf`s field: hidden
conf`s field: Db

SayOp Called result: create Db

get struct[Op] tag[json]: jsonop, error:<nil>

get struct[Op] tag[xml]: xmlOpName, error:<nil>

get struct[nofield] tag[json]: , error:no field named:nofield

相關文章