Golang:反思 - 如何获得一个字段类型的零值 [英] Golang: Reflection - How to get zero value of a field type

查看:538
本文介绍了Golang:反思 - 如何获得一个字段类型的零值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含许多字段的结构体 - 我已经想出了如何使用反射来提取字段名称,值和标记信息。我也想做的是确定一个字段的值是否与字段的默认值不同。



目前,我有这个(有效,但有点臭):

$ $ p $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $' var defaultTime time.Time
var defaultString string
...
//获取字段名称和值
fieldName:= s.Type()。Field(i).Tag .Get(bson)
fieldValue:= valueField.Interface()

//使用反射来确定字段的类型并应用正确的格式
switch fieldValue。 (type){
case time.Time:
if fieldValue!= defaultTime {
qsMap [fieldName] = fieldValue
}
大小写字符串:
if fieldValue!= defaultString {
qsMap [fieldName] = fieldValue
}
...
}

在我看来,应该有一种方法可以避免在这种情况下的类型切换 - 我想要做的是构建一个具有不同值的字段/值的映射从它们的默认零值开始,如下所示:

  //不起作用 - 即,如果字符串类型的fieldValue是与等比较
如果fieldValue!= reflect.Zero(reflect.Type(fieldValue)){
qsMap [fieldName] = fieldValue
}

有没有一种优雅的方式可以实现这一目标?



谢谢!

解决方案

对于支持相等操作的类型,您可以比较 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我:= 0;我< v.Len(); i ++ {
z = z&& isZero(v.Index(i))
}
return z
case reflect.Struct:
z:= true
for i:= 0;我< v.NumField(); i ++ {
z = z&& isZero(v.Field(i))
}
return z
}
//直接比较其他类型:
z:= reflect.Zero(v.Type ))
return v.Interface()== z.Interface()
}


I have a struct containing many fields - I've figured out how to extract the field name, value, and tag information using reflection. What I also want to do is to determine if the value of a field is different from the field's default value.

Currently, I have this (works, but a bit smelly):

...
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
}
...
}

Seems to me that there should be a way to avoid the type switch in this case - what I'm trying to do is build up a map of field/values that have a value different from their default zero value, something like:

// 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
}

Is there an elegant way to accomplish this?

Thanks!

解决方案

For types that support the equality operation, you can just compare interface{} variables holding the zero value and field value. Something like this:

v.Interface() == reflect.Zero(v.Type()).Interface()

For functions, maps and slices though, this comparison will fail, so we still need to include some special casing. Further more, while arrays and structs are comparable, the comparison will fail if they contain non-comparable types. So you probably need something like:

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()
}

这篇关于Golang:反思 - 如何获得一个字段类型的零值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆