反射提供了一种可以 *** 作任意类型数据结构的能力。通过反射你可以实现对任意类型的深度复制,可以对任意类型执行自定义的 *** 作。另外由于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的反射机制所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)