我有一个包含许多字段的结构 - 我已经想出如何使用反射提取字段名称,值和标记信息.我还想做的是确定字段的值是否与字段的默认值不同.
目前,我有这个(工作,但有点臭):
...
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
}
...
}
Run Code Online (Sandbox Code Playgroud)
在我看来,在这种情况下应该有一种避免类型切换的方法 - 我要做的是建立一个字段/值的映射,其值与其默认的零值不同,如:
// 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
}
Run Code Online (Sandbox Code Playgroud)
有一种优雅的方式来实现这一目标吗?
谢谢!
Jam*_*dge 25
对于支持相等操作的类型,您只需比较interface{}保持零值和字段值的变量.像这样的东西:
v.Interface() == reflect.Zero(v.Type()).Interface()
Run Code Online (Sandbox Code Playgroud)
但是对于函数,贴图和切片,这种比较会失败,所以我们仍然需要包含一些特殊的套管.此外,虽然数组和结构是可比较的,但如果它们包含不可比较的类型,则比较将失败.所以你可能需要这样的东西:
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()
}
Run Code Online (Sandbox Code Playgroud)
小智 7
我无法发表评论,但如果您提供包含任何未导出字段的结构,则接受的答案会引起恐慌.我发现的技巧是检查字段是否可以设置 - 基本上忽略任何未导出的字段.
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++ {
if v.Field(i).CanSet() {
z = z && isZero(v.Field(i))
}
}
return z
case reflect.Ptr:
return isZero(reflect.Indirect(v))
}
// Compare other types directly:
z := reflect.Zero(v.Type())
result := v.Interface() == z.Interface()
return result
}
Run Code Online (Sandbox Code Playgroud)
只需使用
reflect.Value.IsZero()
Run Code Online (Sandbox Code Playgroud)
Go 1.13 中引入,2019-09-03 发布(该问题持续了 5 年)。
(我也错过了,所以我先到了这里。)