在go中对于一个变量,主要包含两个信息变量类型(type)和变量值(value)
可以通过reflect包在运行的时候动态获取变量信息,并能够进行操作
对于Type可以通过reflect.TypeOf()获取到变量的类型信息
reflect.TypeOf()返回的是一个Type类型,里面保存了类型的信息
通过reflect.ValueOf()来获取到变量的值部分
reflect.ValueOf()返回的是一个Value类型
可以通过Value.Kind()获取到该变量大概的类型
go中的断言可以将一个未知的类型转换为指定的类型
通过结合反射和断言,我们可以实现这样的一个功能
// UpdateFieldMap 获取更新字段键值对,除了在empty记录的字段整数类型为0或者string类型为空默认不更新
func UpdateFieldMap(in any, empty map[string]struct{}) map[string]any {
out := make(map[string]any)
if empty == nil {
empty = make(map[string]struct{})
}
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
panic(fmt.Errorf("ToMap only accepts structs; got %T", v))
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// 获取字段的值
fieldValue := v.Field(i)
// 获取字段的类型
//fieldType := fieldValue.Type()
columns := strings.Split(typ.Field(i).Tag.Get("gorm"), ";")
column := ""
for _, s := range columns {
if strings.HasPrefix(s, "column:") {
column = s[7:]
}
}
switch fieldValue.Kind() {
case reflect.Int:
//fmt.Println(column, fieldValue.Interface().(int))
val := fieldValue.Interface().(int)
_, ok := empty[column]
if val != 0 || ok {
out[column] = val
}
case reflect.String:
val := fieldValue.Interface().(string)
_, ok := empty[column]
if val != "" || ok {
out[column] = val
}
case reflect.Struct:
if fieldValue.Type() == reflect.TypeOf(time.Time{}) {
// 处理 time.Time 类型
val := fieldValue.Interface().(time.Time)
_, ok := empty[column]
if !val.IsZero() || ok {
out[column] = val
}
}
}
}
return out
}