...
1 package funk
2
3 import (
4 "reflect"
5 "strings"
6 )
7
8
9 func Get(out interface{}, path string, opts ...option) interface{} {
10 options := newOptions(opts...)
11
12 result := get(reflect.ValueOf(out), path)
13
14 if result.Kind() != reflect.Invalid && result.CanInterface() {
15
16 if !options.allowZero && result.IsZero() {
17 return nil
18 }
19
20 if result.Kind() == reflect.Ptr && result.IsNil() {
21 return nil
22 }
23
24 return result.Interface()
25 }
26
27 return nil
28 }
29
30
31 func GetOrElse(v interface{}, def interface{}) interface{} {
32 val := reflect.ValueOf(v)
33 if v == nil || (val.Kind() == reflect.Ptr && val.IsNil()) {
34 return def
35 } else if val.Kind() != reflect.Ptr {
36 return v
37 }
38 return val.Elem().Interface()
39 }
40
41 func get(value reflect.Value, path string) reflect.Value {
42 if value.Kind() == reflect.Slice || value.Kind() == reflect.Array {
43 var resultSlice reflect.Value
44
45 length := value.Len()
46
47 if length == 0 {
48 zeroElement := reflect.Zero(value.Type().Elem())
49 pathValue := get(zeroElement, path)
50 value = reflect.MakeSlice(reflect.SliceOf(pathValue.Type()), 0, 0)
51
52 return value
53 }
54
55 for i := 0; i < length; i++ {
56 item := value.Index(i)
57
58 resultValue := get(item, path)
59
60 if resultValue.Kind() == reflect.Invalid || resultValue.IsZero() {
61 continue
62 }
63
64 resultType := resultValue.Type()
65
66 if resultSlice.Kind() == reflect.Invalid {
67 resultType := reflect.SliceOf(resultType)
68
69 resultSlice = reflect.MakeSlice(resultType, 0, 0)
70 }
71
72 resultSlice = reflect.Append(resultSlice, resultValue)
73 }
74
75
76 if resultSlice.Kind() != reflect.Invalid && resultSlice.Type().Elem().Kind() == reflect.Slice {
77 return flattenDeep(resultSlice)
78 }
79
80 return resultSlice
81 }
82
83 parts := strings.Split(path, ".")
84
85 for _, part := range parts {
86 value = redirectValue(value)
87 kind := value.Kind()
88
89 switch kind {
90 case reflect.Invalid:
91 continue
92 case reflect.Struct:
93 value = value.FieldByName(part)
94 case reflect.Map:
95 value = value.MapIndex(reflect.ValueOf(part))
96 case reflect.Slice, reflect.Array:
97 value = get(value, part)
98 default:
99 return reflect.ValueOf(nil)
100 }
101 }
102
103 return value
104 }
105
View as plain text