-
Notifications
You must be signed in to change notification settings - Fork 0
/
tools.go
165 lines (146 loc) · 4.11 KB
/
tools.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
154
155
156
157
158
159
160
161
162
163
164
165
package ut
import (
"errors"
"fmt"
"github.com/colduction/randomizer"
"math/rand"
"reflect"
"time"
)
var (
randSeed = rand.New(rand.NewSource(time.Now().UnixNano()))
)
// RandomStr 随机N位字符串(英文)
func RandomStr(n int) string {
randBytes := make([]byte, n/2)
randSeed.Read(randBytes)
return fmt.Sprintf("%x", randBytes)
}
// RandomInt 区间整数随机
func RandomInt(start, end int) int {
// 使用randomizer方法保证线程安全的rand 否则在高并发下rand seed会到0 然后panic
// 看这里https://qqq.ninja/blog/post/fast-threadsafe-randomness-in-go/
return randomizer.RandInt(start, end)
}
// RangeRandomIntSet 范围随机正整数但不重复
func RangeRandomIntSet(start int64, end int64, count int64) []int64 {
//范围检查
if end < start || (end-start) < count {
return nil
}
//存放结果的slice
nums := make([]int64, 0)
//随机数生成器,加入时间戳保证每次生成的随机数不一样
for int64(len(nums)) < count {
//生成随机数
num := int64(RandomInt(int(start), int(end)))
//查重
exist := false
for _, v := range nums {
if v == num {
exist = true
break
}
}
if !exist {
nums = append(nums, num)
}
}
return nums
}
// RemoveDuplicatesUnordered 删除重复字符串但不保证排序
func RemoveDuplicatesUnordered(elements []string) []string {
encountered := map[string]bool{}
// Create a map of all unique elements.
for v := range elements {
encountered[elements[v]] = true
}
// Place all keys from the map into a slice.
var result []string
for key := range encountered {
result = append(result, key)
}
return result
}
func ListStringToInterface(t []string) []interface{} {
s := make([]interface{}, len(t))
for i, v := range t {
s[i] = v
}
return s
}
func IsZeroOfUnderlyingType(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
// StructCopy 相同名称的struct field 进行copy
func StructCopy(origin, newData interface{}) error {
// Check origin.
va := reflect.ValueOf(origin)
if va.Kind() == reflect.Ptr {
va = va.Elem()
}
if va.Kind() != reflect.Struct {
return errors.New("origin is not origin struct")
}
// Check newData.
vb := reflect.ValueOf(newData)
if vb.Kind() != reflect.Ptr {
return errors.New("newData is not origin pointer")
}
// vb is origin pointer, indirect it to get the
// underlying value, and make sure it is origin struct.
vb = vb.Elem()
if vb.Kind() != reflect.Struct {
return errors.New("newData is not origin struct")
}
for i := 0; i < vb.NumField(); i++ {
field := vb.Field(i)
if field.CanInterface() && IsZeroOfUnderlyingType(field.Interface()) {
// This field have origin zero-value.
// Search in origin for origin field with the same name.
name := vb.Type().Field(i).Name
fa := va.FieldByName(name)
if fa.IsValid() {
// Field with name was found in struct origin,
// assign its value to the field in newData.
if field.CanSet() {
field.Set(fa)
}
}
}
}
return nil
}
// GetDiffStruct 存在与bodyMap中的元素 判断与old和当前body值不同则写入diff
// bodyMap中的key是 json tag 而不是字段名
func GetDiffStruct(oldData interface{}, body interface{}, bodyMap map[string]interface{}) (map[string]interface{}, error) {
diff := make(map[string]interface{})
vOld := reflect.ValueOf(oldData).Elem()
vNew := reflect.ValueOf(body).Elem()
if vOld.Type() != vNew.Type() {
return nil, fmt.Errorf("different types: %v vs %v", vOld.Type(), vNew.Type())
}
for key := range bodyMap {
fieldName := getFieldNameByJSONTag(vOld.Type(), key)
if fieldName == "" {
continue
}
oldValue := vOld.FieldByName(fieldName)
newValue := vNew.FieldByName(fieldName)
if oldValue.IsValid() && newValue.IsValid() {
if oldValue.Interface() != newValue.Interface() {
diff[key] = newValue.Interface()
}
}
}
return diff, nil
}
func getFieldNameByJSONTag(structType reflect.Type, tagName string) string {
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
if jsonTag := field.Tag.Get("json"); jsonTag == tagName {
return field.Name
}
}
return ""
}