-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtravers.go
64 lines (56 loc) · 1.2 KB
/
travers.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
package domain
import (
"fmt"
"reflect"
"strconv"
)
type Traverser[T any] func(T) (bool, error)
func Travers[T any](v any, t Traverser[T]) error {
rv := reflect.ValueOf(v)
return travers(rv, rv.Type().Name(), t)
}
func travers[T any](rv reflect.Value, n string, fn Traverser[T]) error {
if rv.IsZero() {
return nil
}
var t, rt = [0]T{}, rv.Type()
fmt.Println(n)
if rt.AssignableTo(reflect.TypeOf(t).Elem()) {
ok, err := fn(rv.Interface().(T))
if err != nil {
return err
}
if !ok {
return nil
}
}
switch rv.Kind() {
case reflect.Struct:
for i := 0; i < rv.NumField(); i += 1 {
if !rt.Field(i).IsExported() {
continue
}
if err := travers(rv.Field(i), rt.Field(i).Name, fn); err != nil {
return err
}
}
return nil
case reflect.Map:
for _, key := range rv.MapKeys() {
if err := travers(rv.MapIndex(key), key.String(), fn); err != nil {
return err
}
}
case reflect.Slice:
for i := 0; i < rv.Len(); i += 1 {
if err := travers(rv.Index(i), strconv.Itoa(i), fn); err != nil {
return err
}
}
case reflect.Ptr:
return travers(rv.Elem(), rt.Name(), fn)
case reflect.Interface:
return travers(rv.Elem(), rt.Name(), fn)
}
return nil
}