我想在将JSON对象解组到其中之后迭代struct
的字段,并检查其值未设置的字段(即为空)。
我可以得到每个字段的值,并将其与相应类型的reflect.Zero
值进行比较
json.Unmarshal([]byte(str), &res)
s := reflect.ValueOf(&res).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
v := reflect.ValueOf(f.Interface())
if (reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())) {
....
但问题当然是,这对bool
或int
值不适用。如果在JSON中将bool
字段设置为false
或将int
字段设置为0
,则它们将等于其类型的零值。上述检查将考虑未初始化的字段,即使它们实际上具有值集。
我知道解决这个问题的一种方法是使用指针,但我只是不知道在这种情况下如何使用reflect.Value
类型,而不是实际的struct
。
正如您所提到的,您可以使用指针。
json
包可以为您处理指针的解组值。你没有包含你试图解组的json有效负载,或者你正在解组的结构,所以我已经编写了一个例子。
// json
{
"foo": true,
"number_of_foos": 14
}
// go struct
type Foo struct {
Present bool `json:"foo"`
Num int `json:"number_of_foos"`
}
如果缺少foo
或number_of_foos
键,那么正如您正确观察到的那样,将使用零值(false
/ 0
)。一般来说,最好的建议是使用零值。创建结构,使false
的零值有用,而不是痛苦。这并不总是可行的,因此将Foo
结构中的字段类型更改为指针将允许您检查您所追求的3个案例。
这是带指针的相同结构:
// go struct
type Foo struct {
Present *bool `json:"foo"`
Num *int `json:"number_of_foos"`
}
现在,您可以使用fooStruct.Present != nil
检查值是否存在,如果该条件成立,您可以假设该字段中的值是您想要的值。
无需使用反射包。
另一种做法是通过实施json.Unmarshaler
。
type MaybeInt struct {
Present bool
Value int
}
func (i *MaybeInt) UnmarshalJSON(bs []byte) error {
if e := json.Unmarshal(bs, &i.Value); e != nil {
return e
}
i.Present = true
return nil
}
然后,您可以在顶级结构中使用MaybeInt
:
type Top struct {
N MaybeInt `json:"n"`
M MaybeInt `json:"m"`
}
func main() {
t := Top{}
if e := json.Unmarshal([]byte(` { "n": 4930 } `), &t); e != nil {
panic(e)
}
fmt.Println(t.N, t.M)
}
看到它在playground上工作
尝试使用golang验证程序包。验证程序包提供了一个必需的属性,可以根据您的需要执行所需的工作。 https://godoc.org/gopkg.in/go-playground/validator.v9所需属性的官方文档说明:
这将验证该值不是数据类型的默认零值。对于数字,确保值不为零。对于字符串,确保值不是“”。对于切片,贴图,指针,接口,通道和函数,确保值不为零。
说明相同的例子可以在:https://github.com/go-playground/validator/blob/v9/_examples/struct-level/main.go看到。
希望这能解决您的要求。