github.com/openimsdk/tools@v0.0.49/mw/replace_nil.go (about) 1 package mw 2 3 import ( 4 "github.com/openimsdk/tools/utils/datautil" 5 "reflect" 6 ) 7 8 // ReplaceNil initialization nil values. 9 // e.g. Slice will be initialized as [],Map/interface will be initialized as {} 10 func ReplaceNil(data any) { 11 v := reflect.ValueOf(data) 12 13 replaceNil(v) 14 } 15 16 func replaceNil(v reflect.Value) { 17 switch v.Kind() { 18 case reflect.Pointer: 19 if v.IsNil() { 20 // Handle multi-level pointers 21 elemKind := v.Type().Elem().Kind() 22 if elemKind == reflect.Pointer { 23 v.Set(reflect.New(v.Type().Elem())) 24 } 25 } 26 replaceNil(v.Elem()) 27 case reflect.Slice: 28 if v.IsNil() { 29 v.Set(reflect.MakeSlice(v.Type(), 0, 0)) 30 } 31 case reflect.Map: 32 if v.IsNil() { 33 v.Set(reflect.MakeMap(v.Type())) 34 } 35 case reflect.Struct: 36 for i := 0; i < v.NumField(); i++ { 37 field := v.Field(i) 38 fieldType := v.Type().Field(i) 39 40 // Check if the field is exported 41 if fieldType.IsExported() { 42 replaceNil(field) 43 } 44 } 45 case reflect.Interface: 46 if !v.IsNil() && !shouldReplace(v) { 47 // If the interface is already initialized, recursively replace the internal nils 48 replaceNil(v.Elem()) 49 } else { 50 // If the interface is not initialized, the struct will be initialized as {} 51 realType := getRealType(v.Interface()) 52 if realType == nil { 53 // Invalid type 54 return 55 } 56 switch realType.Kind() { 57 case reflect.Slice: 58 v.Set(reflect.MakeSlice(realType, 0, 0)) 59 case reflect.Map: 60 v.Set(reflect.MakeMap(realType)) 61 case reflect.Struct: 62 v.Set(reflect.New(reflect.TypeOf(struct{}{}))) 63 default: 64 } 65 } 66 default: 67 return 68 } 69 } 70 71 // getRealType determines the underlying type. 72 func getRealType(data any) reflect.Type { 73 t := reflect.TypeOf(data) 74 if t == nil { 75 return t 76 } 77 for t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface { 78 t = t.Elem() 79 } 80 return t 81 } 82 83 // shouldReplace determines whether internal replacement is needed, 84 // checks if the underlying component has already been initialized. 85 func shouldReplace(v reflect.Value) bool { 86 if !v.IsValid() { 87 return true 88 } 89 if datautil.Contain(v.Kind(), []reflect.Kind{reflect.Slice, reflect.Map}...) && v.IsNil() { 90 return true 91 } 92 switch v.Kind() { 93 case reflect.Ptr: 94 return shouldReplace(v.Elem()) 95 case reflect.Interface: 96 return shouldReplace(v.Elem()) 97 default: 98 return false 99 } 100 }