-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathxreflect.go
153 lines (135 loc) · 3.53 KB
/
xreflect.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Package xreflect is a reflection utility library.
//
// The xreflect package aims to provide developers with high-level abstractions over the Go standard reflect library.
// This library's API is often considered low-level and unintuitive, making simple tasks like accessing structure
// field values or tags more complex than necessary.
package xreflect
import (
"fmt"
"reflect"
)
// NewInstance returns a new instance of the same type as the input value.
// The returned value will contain the zero value of the type.
// If obj type is a slice, chan, etc. , it will create an instance with the same capacity.
func NewInstance(obj interface{}) interface{} {
if obj == nil {
return nil
}
entity := reflect.ValueOf(obj)
switch entity.Kind() {
case reflect.Ptr:
entity = reflect.New(entity.Elem().Type())
break
case reflect.Chan:
entity = reflect.MakeChan(entity.Type(), entity.Cap())
break
case reflect.Map:
entity = reflect.MakeMap(entity.Type())
break
case reflect.Slice:
entity = reflect.MakeSlice(entity.Type(), 0, entity.Cap())
break
default:
entity = reflect.New(entity.Type()).Elem()
}
return entity.Interface()
}
// Type returns the reflection type of obj.
// If obj is a pointer, it will be automatically dereferenced once.
func Type(obj interface{}) reflect.Type {
if obj == nil {
return nil
}
if v, ok := obj.(reflect.Type); ok {
return v
}
if v, ok := obj.(reflect.Value); ok {
return v.Type()
}
if reflect.TypeOf(obj).Kind() == reflect.Ptr {
return reflect.TypeOf(obj).Elem()
}
return reflect.TypeOf(obj)
}
// TypePenetrateElem performs the same functionality as Type, but it will parse through all pointers
// until the final type is reached.
func TypePenetrateElem(obj interface{}) reflect.Type {
if obj == nil {
return nil
}
ty := Type(obj)
for ty.Kind() == reflect.Ptr {
ty = ty.Elem()
}
return ty
}
// Value returns the reflection value of obj.
// If obj is a pointer, it will be automatically dereferenced once.
func Value(obj interface{}) reflect.Value {
var empty reflect.Value
if obj == nil {
return empty
}
if v, ok := obj.(reflect.Value); ok {
return v
}
if reflect.TypeOf(obj).Kind() == reflect.Ptr {
return reflect.ValueOf(obj).Elem()
}
return reflect.ValueOf(obj)
}
// ValuePenetrateElem performs the same functionality as Value, but it will parse through all pointers
// until the final type is reached.
func ValuePenetrateElem(obj interface{}) reflect.Value {
var empty reflect.Value
if obj == nil {
return empty
}
ty := Value(obj)
for ty.Kind() == reflect.Ptr {
ty = ty.Elem()
}
return ty
}
// GetPkgPath returns the package path of obj.
func GetPkgPath(obj interface{}) string {
ty := Type(obj)
if ty == nil {
return ""
}
return ty.PkgPath()
}
// Implements returns whether obj implements the given interface in.
func Implements(obj interface{}, in interface{}) bool {
objType := reflect.TypeOf(obj)
if objType == nil {
return false
}
interfaceType := reflect.TypeOf(in).Elem()
return objType.Implements(interfaceType)
}
func checkField(field reflect.Value, name string) error {
if !field.IsValid() {
return fmt.Errorf("field: %s is invalid", name)
}
if !field.CanSet() {
return fmt.Errorf("field: %s can not set", name)
}
return nil
}
func isSupportedKind(k reflect.Kind, kinds []reflect.Kind) bool {
for _, v := range kinds {
if k == v {
return true
}
}
return false
}
func isSupportedType(obj interface{}, types []reflect.Kind) bool {
for _, t := range types {
if reflect.TypeOf(obj).Kind() == t {
return true
}
}
return false
}