How to get zero value of a field type

后端 未结 3 682
孤街浪徒
孤街浪徒 2021-02-04 04:47

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

相关标签:
3条回答
  • 2021-02-04 05:31

    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()
    }
    
    0 讨论(0)
  • 2021-02-04 05:38

    You can switch on the Kind() of the Value and use the appropriate accessor (many fewer kinds than types). Something like:

    switch valueField.Kind() {
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        if valueField.Int() == 0 {...}
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
        if valueField.Uint() == 0 {...}
    case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
        if valueField.IsNil() {...}
    //add more cases for Float, Bool, String, etc (and anything else listed http://golang.org/pkg/reflect/#Kind )
    }
    

    You could also get a zeroed instance of a value by using reflect.Zero(valueField.Type()) but it is not safe to compare that with valueField since some types (such as slices and maps) do not support equality and would panic.

    0 讨论(0)
  • 2021-02-04 05:41

    I couldn't post a comment, but the accepted answer panics if you provide a struct with any unexported fields. The trick I've found is to check if the field can be set - essentially ignoring any unexported fields.

    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
    }
    
    0 讨论(0)
提交回复
热议问题