【问题标题】:How to know if a variable of arbitrary type is Zero in Golang?如何知道Golang中任意类型的变量是否为零?
【发布时间】:2015-10-14 03:07:53
【问题描述】:

因为并非所有类型都具有可比性,例如一片。所以我们不能这样做

var v ArbitraryType
v == reflect.Zero(reflect.TypeOf(v)).Interface()

【问题讨论】:

    标签: go reflection go-reflect


    【解决方案1】:

    Go 1.13 在reflect 包中引入了Value.IsZero 方法。这是您可以使用它检查零值的方法:

    if reflect.ValueOf(v).IsZero() {
        // v is zero, do something
    }
    

    除了基本类型外,它还适用于 Chan、Func、Array、Interface、Map、Ptr、Slice、UnsafePointer 和 Struct。

    【讨论】:

      【解决方案2】:

      正如 Peter Noyes 指出的那样,您只需要确保您没有比较一个不可比较的类型。幸运的是,reflect 包非常简单:

      func IsZero(v interface{}) (bool, error) {
          t := reflect.TypeOf(v)
          if !t.Comparable() {
              return false, fmt.Errorf("type is not comparable: %v", t)
          }
          return v == reflect.Zero(t).Interface(), nil
      }
      

      查看使用here的示例。

      【讨论】:

        【解决方案3】:

        以下两个都给了我合理的结果(可能是因为它们是相同的?)

        reflect.ValueOf(v) == reflect.Zero(reflect.TypeOf(v)))
        
        reflect.DeepEqual(reflect.ValueOf(v), reflect.Zero(reflect.TypeOf(v)))
        

        例如各种整数 0 风格和未初始化的 structs 是“零”

        遗憾的是,空字符串和数组不是。 nil 给出了一个例外。
        如果需要,您可以对这些进行特殊处理。

        【讨论】:

        • 嗨节奏,感谢您的回复!实际上,== 和 DeepEqual 是不同的。根据 go 文档 reflect.DeepEqual,DeepEqual 适用于可比较和不可比较变量
        • 我还没有理解可比性,我去看看,谢谢。
        【解决方案4】:

        反映

        v 是一个接口时,这取决于你想要什么行为(对于其他类型它是相同的):

        • reflect.ValueOf(v).IsZero()检查界面中boxed的值是否为零
        • reflect.ValueOf(&v).Elem().IsZero() 检查接口变量是否为零

        演示(playground):

        var v interface{} = ""
        fmt.Println(reflect.ValueOf(v).IsZero())           // true, the empty string "" is zero
        fmt.Println(reflect.ValueOf(&v).Elem().IsZero())   // false, the interface itself is not zero
        

        差异是由于ValueOf 的参数是interface{}。如果您传递一个接口,它将取消装箱其中装箱的动态值。 ValueOf 的 Go 文档提醒:

        ValueOf 返回一个新的 Value,初始化为 存储在接口 i 中的具体值

        通过使用ValueOf(&v) 代替“存储在接口i 中的具体值”将是指向v 的指针。然后使用Elem() 取消引用以获取原始值,最后检查IsZero()

        通常情况下,您想要的可能是 reflect.ValueOf(&v).Elem().IsZero(),虽然是 YMMV。

        Go 1.18 和泛型

        使用泛型,您可以通过在var zero T*new(T) 上使用== 运算符来检查变量是否为零值。类型参数必须是可比较的comparable 约束或可比较类型的类型集)。

        func IsZeroVar[T ~int64 | ~string](v T) bool {
            var zero T
            return v == zero
        }
        
        func IsZeroNew[T ~int64 | ~string](v T) bool {
            return v == *new(T)
        }
        

        如果类型参数不可比较,则必须回退到反射,如上所示。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-09-04
          • 1970-01-01
          • 2022-01-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多