英文:
How can I know that the field is set to null?
问题
我想要在 JSON 字段包含 null 值时输出一个错误。我该如何做呢?我已经尝试了 "encoding/json" 包,也许我需要另一个库。
代码示例:
package main
import (
    "encoding/json"
    "fmt"
    "strings"
)
type Item struct {
    Value  *int
}
func main() {
    var jsonBlob = `[
        {},
        {"Value": null},
        {"Value": 0},
        {"Value": 1}
    ]`
    var items []Item
    err := json.NewDecoder(strings.NewReader(jsonBlob)).Decode(&items)
    if err != nil {
        fmt.Println("error:", err)
    }
    for _, a := range items {
        if a.Value != nil {
            fmt.Println(*a.Value)
        } else {
            fmt.Println("<error>")
        }
    }
}
我得到的输出是:
<nil>
<nil>
0
1
我想要的输出是:
<nil>
<error>
0
1
请帮忙看看。非常感谢!
英文:
I want to output an error if the field in json contains a value of null. How can I do it? I have tried "encoding/json". Maybe I need another library.
Code example:
package main
import (
    "encoding/json"
    "fmt"
    "strings"
)
type Item struct {
    Value  *int
}
func main() {
    var jsonBlob = `[
        {},
        {"Value": null},
        {"Value": 0},
        {"Value": 1}
    ]`
    var items []Item
    err := json.NewDecoder(strings.NewReader(jsonBlob)).Decode(&items)
    if err != nil {
        fmt.Println("error:", err)
    }
    for _, a := range items {
        if a.Value != nil {
            fmt.Println(*a.Value)
        } else {
            fmt.Println(a.Value)
        }
    }
}
I got:
<nil>
<nil>
0
1
I want:
<nil>
<error>
0
1
Please help. Many thanks!
答案1
得分: 4
如果你想控制类型的反序列化过程,你可以实现json.Unmarshaler接口。
由于映射(map)允许你区分未设置的值和null值,首先将其反序列化为通用的map[string]interface{}类型,可以让你在不对JSON进行标记化的情况下检查值。
type Item struct {
    Value *int
}
func (i *Item) UnmarshalJSON(b []byte) error {
    tmp := make(map[string]interface{})
    err := json.Unmarshal(b, &tmp)
    if err != nil {
        return err
    }
    val, ok := tmp["Value"]
    if ok && val == nil {
        return errors.New("Value cannot be nil")
    }
    if !ok {
        return nil
    }
    f, ok := val.(float64)
    if !ok {
        return fmt.Errorf("unexpected type %T for Value", val)
    }
    n := int(f)
    i.Value = &n
    return nil
}
你可以在这里查看代码示例:https://play.golang.org/p/MNDsQpfEJA
英文:
If you want to control how a type is unmarshaled, you can implement json.Unmarshaler
Since a map allows you to tell the difference between an unset value, and a null value, unmarshaling first into a generic map[string]interface{} will allow you to inspect the values without tokenizing the JSON.
type Item struct {
	Value *int
}
func (i *Item) UnmarshalJSON(b []byte) error {
	tmp := make(map[string]interface{})
	err := json.Unmarshal(b, &tmp)
	if err != nil {
		return err
	}
	val, ok := tmp["Value"]
	if ok && val == nil {
		return errors.New("Value cannot be nil")
	}
	if !ok {
		return nil
	}
	f, ok := val.(float64)
	if !ok {
		return fmt.Errorf("unexpected type %T for Value", val)
	}
	n := int(f)
	i.Value = &n
	return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论