我有一个包含许多字段的结构-我已经弄清楚了如何使用反射来提取字段名称,值和标签信息。我还想确定一个字段的值是否不同于该字段的默认值。
目前,我有这个(有效,但有点臭):
... qsMap := make(map[string]interface{}) var defaultTime time.Time var defaultString string ... // get the field name and value fieldName := s.Type().Field(i).Tag.Get("bson") fieldValue := valueField.Interface() // use reflection to determine the TYPE of the field and apply the proper formatting switch fieldValue.(type) { case time.Time: if fieldValue != defaultTime { qsMap[fieldName] = fieldValue } case string: if fieldValue != defaultString { qsMap[fieldName] = fieldValue } ... }
在我看来,在这种情况下应该有一种避免类型切换的方法-我正在尝试做的是建立一个字段/值映射,其值不同于默认的零值,例如:
// doesn't work -- i.e., if fieldValue of type string would be compared against "", etc. if fieldValue != reflect.Zero(reflect.Type(fieldValue)) { qsMap[fieldName] = fieldValue }
是否有一种优雅的方式来实现这一目标?
谢谢!
对于支持相等操作的类型,您可以只比较interface{}包含零值和字段值的变量。像这样:
interface{}
v.Interface() == reflect.Zero(v.Type()).Interface()
但是对于函数,地图和切片,此比较将失败,因此我们仍然需要包括一些特殊的大小写。此外,尽管数组和结构是可比较的,但如果它们包含不可比较的类型,则比较将失败。因此,您可能需要类似以下内容:
func isZero(v reflect.Value) bool { switch v.Kind() { case reflect.Func, reflect.Map, reflect.Slice: return v.IsNil() case reflect.Array: z := true for i := 0; i < v.Len(); i++ { z = z && isZero(v.Index(i)) } return z case reflect.Struct: z := true for i := 0; i < v.NumField(); i++ { z = z && isZero(v.Field(i)) } return z } // Compare other types directly: z := reflect.Zero(v.Type()) return v.Interface() == z.Interface() }