-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathexample_test.go
139 lines (126 loc) · 2.82 KB
/
example_test.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
package reflectutils_test
import (
"fmt"
"reflect"
"github.com/muir/reflectutils"
"github.com/pkg/errors"
)
type S struct {
I1 int
D T2
S string
M T
}
type T struct {
I2 int
}
type T2 struct {
I3 int
I4 int
}
func makeIntDoubler(t reflect.Type) func(v reflect.Value) {
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
panic("makeIntDoubler only supports pointers to structs")
}
var ints []reflect.StructField
reflectutils.WalkStructElements(t, func(f reflect.StructField) bool {
if f.Type.Kind() == reflect.Int {
ints = append(ints, f)
}
return true
})
return func(v reflect.Value) {
v = v.Elem()
for _, f := range ints {
i := v.FieldByIndex(f.Index)
i.SetInt(int64(i.Interface().(int)) * 2)
}
}
}
func makeIntDoublerWithError(t reflect.Type) (func(v reflect.Value), error) {
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
panic("makeIntDoublerWithError only supports pointers to structs")
}
var ints []reflect.StructField
err := reflectutils.WalkStructElementsWithError(t, func(f reflect.StructField) error {
if f.Type.Kind() == reflect.Int {
ints = append(ints, f)
}
if f.Type.Kind() == reflect.String {
return errors.Errorf("error on string, and stop walk")
}
return nil // return nil will recurse on a field that is struct
})
return func(v reflect.Value) {
v = v.Elem()
for _, f := range ints {
i := v.FieldByIndex(f.Index)
i.SetInt(int64(i.Interface().(int)) * 2)
}
}, err
}
func makeIntDoublerNoRecursive(t reflect.Type) (func(v reflect.Value), error) {
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
panic("makeIntDoublerNoRecursive only supports pointers to structs")
}
var ints []reflect.StructField
err := reflectutils.WalkStructElementsWithError(t, func(f reflect.StructField) error {
if f.Type.Kind() == reflect.Int {
ints = append(ints, f)
}
return reflectutils.DoNotRecurseSignalErr
})
return func(v reflect.Value) {
v = v.Elem()
for _, f := range ints {
i := v.FieldByIndex(f.Index)
i.SetInt(int64(i.Interface().(int)) * 2)
}
}, err
}
func Example() {
s := S{
I1: 3,
D: T2{
I3: 2,
I4: 6,
},
S: "string",
M: T{
I2: 5,
},
}
v := reflect.ValueOf(&s)
doubler := makeIntDoubler(v.Type())
doubler(v)
fmt.Printf("%v\n", v.Interface())
doubler, err := makeIntDoublerNoRecursive(v.Type())
doubler(v)
fmt.Printf("%v\n", v.Interface())
fmt.Printf("%v", err)
// Output:
// &{6 {4 12} string {10}}
// &{12 {4 12} string {10}}
// <nil>
}
func ExampleError() {
s := S{
I1: 3,
D: T2{
I3: 2,
I4: 6,
},
S: "string",
M: T{
I2: 5,
},
}
v := reflect.ValueOf(&s)
doubler, err := makeIntDoublerWithError(v.Type())
doubler(v)
fmt.Printf("%v\n", v.Interface())
fmt.Printf("%v", err)
// Output:
// &{6 {4 12} string {5}}
// error on string, and stop walk
}