golang的反射机制

golang的反射机制,第1张

概述go反射 什么是反射?使用反射可以实现什么功能? 反射提供了一种可以 *** 作任意类型数据结构的能力。通过反射你可以实现对任意类型的深度复制,可以对任意类型执行自定义的 *** 作。另外由于golang可以给结构体定义tag熟悉,结合反射,于是就可以实现结构体与数据库表、结构体与json对象之间的相互转换。 使用反射需要注意什么事情? 使用反射时需要先确定要 *** 作的值是否是期望的类型,是否是可以进行“赋值” *** 作的 go反射 什么是反射?使用反射可以实现什么功能?

反射提供了一种可以 *** 作任意类型数据结构的能力。通过反射你可以实现对任意类型的深度复制,可以对任意类型执行自定义的 *** 作。另外由于golang可以给结构体定义tag熟悉,结合反射,于是就可以实现结构体与数据库表、结构体与Json对象之间的相互转换。

使用反射需要注意什么事情?

使用反射时需要先确定要 *** 作的值是否是期望的类型,是否是可以进行“赋值” *** 作的,否则reflect包将会毫不留情的产生一个panic。

struct initializer示例

go-struct-initializer 是我在学习golang反射过程中实现的一个可以根据struct tag初始化结构体的go library,这里对其中用到的反射技术做一下说明

package structinitializerimport (    "reflect"    "fmt"    "strconv"    "strings")const (    ERROR_NOT_A_POINTER = "NotAPointer"    ERROR_NOT_IMPLEMENT = "NotImplement"    ERROR_POINTE_TO_NON_STRUCT = "PointToNonStruct"    ERROR_TYPE_CONVERSION_Failed = "TypeConversionFailed"    ERROR_MulTI_ERRORS_FOUND = "MultIErrorsFound")type Error struct {    Reason  string    Message string    Stack   string}func NewError(reason,message string,stack string) error {    return &Error{reason,message,stack}}func mergedError(errors []error,stackname string) error {    if len(errors) == 0 {        return nil    }    if len(errors) == 1 {        return errors[0]    }    points := make([]string,len(errors))    for i,err := range errors {        points[i] = fmt.Sprintf("* %s",err)    }    return &Error{        ERROR_MulTI_ERRORS_FOUND,strings.Join(points,"\n"),stackname,}}func (e *Error) Error() string {    if e.Stack == "" {        return fmt.Sprintf("%s: %s",e.Reason,e.Message)    }    return fmt.Sprintf("%s:(%s) %s",e.Stack,e.Message)}type InitialiserConfig struct {    Tagname string}type Initialiser struct {    config *InitialiserConfig}func NewStructinitialiser() Initialiser {    config := InitialiserConfig{        Tagname: "default",}    initialiser := Initialiser{        config: &config,}    return initialiser}func (self *Initialiser) initialiseInt(stackname,tag string,val reflect.Value) error {    if tag != "" {        i,err := strconv.ParseInt(tag, 10, 64)        if err != nil {            return NewError(                ERROR_TYPE_CONVERSION_Failed,fmt.Sprintf(`"%s" can't convert to int64`,tag),)        }        if val.Int() == 0 {            val.SetInt(int64(i))        }    }    return nil}func (self *Initialiser) initialiseUint(stackname,err := strconv.ParseUint(tag,fmt.Sprintf(`"%s" can't convert to uint64`,)        }        if val.Uint() == 0 {            val.SetUint(uint64(i))  // 设置value        }    }    return nil}func (self *Initialiser) initialiseString(stackname,val reflect.Value) error {    if tag != "" && val.String() == ""{        val.SetString(tag)    }    return nil}// 检查某个结构体是否存在某个域设置了default标签func (self *Initialiser) checkStructHasDefaultValue(typ reflect.Type) bool {    for i:=0; i<typ.NumFIEld(); i++ {        fIEld := typ.FIEld(i)        if fIEld.Tag.Get(self.config.Tagname) != "" {  // 获取struct fIEld的指定tag            return true        }        if fIEld.Type.Kind() == reflect.Struct && self.checkStructHasDefaultValue(fIEld.Type) {  //             return true        }    }    return false}func (self *Initialiser) initialisePtr(stackname,val reflect.Value) error {    if tag == "-" {        return nil    }    typ := val.Type().Elem()    if tag == "" {        if typ.Kind() != reflect.Struct {            return nil        } else if !self.checkStructHasDefaultValue(typ) {            return nil        }    }        // 结构体存在至少一个域设置了default标签才有初始化的必要    realVal := reflect.New(typ)  // 根据结构体类型创建一个新的结构体        // Indirect可以获取到value对应的真实value(指针指向的value)    if err := self.initialise(stackname,tag,reflect.Indirect(realVal)); err != nil {        return err    }    val.Set(realVal)    return nil}func (self *Initialiser) initialise(stackname string,val reflect.Value) error {    typ := val.Type()    kind := typ.Kind()    if kind == reflect.Struct {        return self.initialiseStruct(stackname,val)    }    switch kind {    case reflect.Int:        fallthrough    case reflect.Int8:        fallthrough    case reflect.Int16:        fallthrough    case reflect.Int32:        fallthrough    case reflect.Int64:        return self.initialiseInt(stackname,val)    case reflect.Uint:        fallthrough    case reflect.Uint8:        fallthrough    case reflect.Uint16:        fallthrough    case reflect.Uint32:        fallthrough    case reflect.Uint64:        fallthrough    case reflect.Uintptr:        return self.initialiseUint(stackname,val)    case reflect.String:        return self.initialiseString(stackname,val)    case reflect.Ptr:        return self.initialisePtr(stackname,val)    default:        return NewError(ERROR_NOT_IMPLEMENT,"not implement",stackname)    }    return NewError(ERROR_NOT_IMPLEMENT,stackname)}func (self *Initialiser) initialiseStruct(stackname string,structVal reflect.Value) error {    structs := make([]reflect.Value, 1, 5)    structs[0] = structVal    errors := make([]error, 0)    for len(structs) > 0 {        structVal := structs[0]        structs = structs[1:]        structTyp := structVal.Type() // 结构体类型信息        for i:=0; i<structTyp.NumFIEld(); i++ { // 循环结构体的所有域             structFIEld := structTyp.FIEld(i) // 获取结构体域信息            tag := structFIEld.Tag // 获取结构体域的标签            defaultTag := tag.Get(self.config.Tagname);            if structFIEld.Anonymous {  // 这个域是一个结构体组合                structs = append(structs,structVal.FIEld(i))                continue            }            fIEldname := structFIEld.name // 获取结构体域的名字            if stackname != "" {                fIEldname = fmt.Sprintf("%s.%s",fIEldname)            }            err := self.initialise(                fIEldname,defaultTag,structVal.FIEld(i),// 获取结构体域对应的值信息            )            if err != nil {                errors = append(errors,err)            }        }    }    return mergedError(errors,stackname)}func (self *Initialiser) Initialise(inf interface{}) error {    typ := reflect.TypeOf(inf)    kind := typ.Kind() // kind与type的区别在于:kind无法区分基本类型的别名    if kind != reflect.Ptr { // 只有指针才能执行初始化 *** 作        return NewError(            ERROR_NOT_A_POINTER,fmt.Sprintf("%s not a pointer",typ),"",)    }    val := reflect.ValueOf(inf).Elem() // 获取指针对应的值信息    kind = val.Kind()    if kind != reflect.Struct {        return NewError(            ERROR_POINTE_TO_NON_STRUCT,fmt.Sprintf("%s point to non struct",)    }    return self.initialiseStruct(val.Type().name(),val)}func InitializeStruct(struct_ interface{}) error {    initialiser := NewStructinitialiser()    return initialiser.Initialise(struct_)}
package structinitializerimport (    "testing"    "fmt"    "reflect")type ValIDator interface {    ValID() bool}type TnormStruct struct  {    AInt int    AStr string}type TStruct struct {    AInt int `default:"10"`    AStr string `default:"hello"`}func (self *TStruct) ValID() bool {    return self.AStr == "hello" && self.AInt == 10}type TWrongStruct struct {    AInt int `default:"hhhhh"`    AStr string `default:"hello"`}func (self *TWrongStruct) ValID() bool {    return false}type TEmbeddStruct struct  {    AStruct TStruct    AInt int `default:"101"`}func (self *TEmbeddStruct) ValID() bool {    return self.AStruct.ValID() && self.AInt == 101}type TEmbeddStruct2 struct  {    AStruct TStruct    AInt int}type TAnonymousstruct struct  {    TStruct    AUint uint16 `default:"20"`}func (self *TAnonymousstruct) ValID() bool  {    return self.TStruct.ValID() && self.AUint == 20}type TPointerStruct struct {    AStructPtr *TStruct    AIntPtr *int32 `default:"20"`    AStrPtr *string `default:"-"`    AUintPtr *uint    AnormStruct *TnormStruct}func (self *TPointerStruct) ValID() bool {    if self.AStructPtr != nil && self.AStructPtr.ValID() && self.AIntPtr != nil && *self.AIntPtr == 20 && self.AStrPtr == nil && self.AUintPtr == nil && self.AnormStruct == nil {        return true    }    return false}func AssertTrue(t *testing.T,a bool,msg string) {    if !a {        t.Errorf(msg)    }}func TestCheckStructHasDefaultValue(t *testing.T) {    self := NewStructinitialiser()    AssertTrue(t,self.checkStructHasDefaultValue(reflect.TypeOf(TStruct{})),"TStruct check Failed!")    AssertTrue(t,!self.checkStructHasDefaultValue(reflect.TypeOf(TnormStruct{})),"TnormStrcut check succeed!")    AssertTrue(t,self.checkStructHasDefaultValue(reflect.TypeOf(TEmbeddStruct2{})),"TEmbeddStruct2 check Failed!")}func checkerror(t *testing.T,err error,wantReason string) {    if err == nil {        t.Errorf("except non pointer err!")        return    } else {        if err1 := err.(*Error); err1.Reason != wantReason {            t.Errorf("want '%s' but '%s': %s",wantReason,err1.Reason,err1.Message)            return        }    }    fmt.Printf("%#v\n",err)}func TestNonPointer(t *testing.T) {    aStruct := TStruct{}    err := InitializeStruct(aStruct)    checkerror(t,err,ERROR_NOT_A_POINTER)}func TestPointToNonStruct(t *testing.T) {    aInt := 100    err := InitializeStruct(&aInt)    checkerror(t,ERROR_POINTE_TO_NON_STRUCT)}func TestWrongTag(t *testing.T) {    aStruct := TWrongStruct{}    err := InitializeStruct(&aStruct)    checkerror(t,ERROR_TYPE_CONVERSION_Failed)}func TestDefaultSetted(t *testing.T) {    aStruct := TStruct{        AInt: 103,}    err := InitializeStruct(&aStruct)    if err != nil || aStruct.AInt != 103 {        t.Errorf("BOOM!!! rewrite a user setted value? err: %s",err)    }    fmt.Printf("%#v\n",aStruct)}func checkStruct(t *testing.T,v ValIDator) {    err := InitializeStruct(v)    if err != nil {        t.Errorf("unexcept err: %#v,aStruct: %#v\n",v)        return    }    if !v.ValID() {        t.Errorf("init incorret: %#v\n",v)        return    }    fmt.Printf("%#v\n",v)}func TestembeddStruct(t *testing.T) {    aStruct := TEmbeddStruct{}    checkStruct(t,&aStruct)}func TestAnonymousstrct(t *testing.T) {    aStruct := TAnonymousstruct{}    checkStruct(t,&aStruct)}func TestnormalStruct(t *testing.T) {    aStruct := TStruct{}    checkStruct(t,&aStruct)}func TestPointerStruct(t *testing.T) {    aStruct := TPointerStruct{}    checkStruct(t,&aStruct)}
参考 Package reflect The Laws of Reflection 总结

以上是内存溢出为你收集整理的golang的反射机制全部内容,希望文章能够帮你解决golang的反射机制所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1282809.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-09
下一篇 2022-06-09

发表评论

登录后才能评论

评论列表(0条)

保存