Golang空类型和json.Decode()

huangapple go评论89阅读模式
英文:

Golang Null Types and json.Decode()

问题

我目前还没有找到解决这个问题的方法。如果我有一个结构体,我想用来填充来自http.Request的json数据,我无法告诉某些值实际上是什么。例如,如果我传入一个空的json对象,并在一个类似这样的结构体上运行json.Decode...

var Test struct {
    Number int `json:"number"`
}

现在我有一个json对象,据说是以number为键,值为零传递的,而实际上我宁愿什么都不返回。Go语言是否提供了另一种方法,可以让我看到传递了什么JSON数据或者没有传递任何数据。

对不起,我一直在试图解决这个问题已经几天了,它让我抓狂。

谢谢任何帮助。

编辑:

我创建了一个示例来准确描述我所说的问题:http://play.golang.org/p/aPFKSvuxC9

英文:

I have not been able to find a way around this issue currently. If I have a structure i would like to populate with json from a http.Request I have no way to tell for instance what value was actually passed in for some values. For instance if I pass in an empty json object and run json.Decode on a structure that looks like this...

var Test struct {
		Number int `json:"number"`
}

I now have a json object that supposedly was passed with a key of number and a value of zero when in fact I would rather have this return nothing at all. Does go provide another method that would actually allow me to see what JSON has been passed in or not.

Sorry for the rambling I have been trying to figure out how to to this for a few days now and it's driving me nuts.

Thanks for any help.

Edit:

I made this to depict exactly what I am talking about http://play.golang.org/p/aPFKSvuxC9

答案1

得分: 9

你可以使用指针,例如:

func main() {
    var jsonBlob = []byte(`[
        {"Name": "Platypus"},
        {"Name": "Quoll", "Order": 100}
    ]`)
    type Animal struct {
        Name  string
        Order *int
    }
    var animals []Animal
    err := json.Unmarshal(jsonBlob, &animals)
    if err != nil {
        fmt.Println("error:", err)
    }
    for _, a := range animals {
        if a.Order != nil {
            fmt.Printf("got order, %s : %d\n", a.Name, *a.Order)
        }
    }
}

请注意,这是一个示例代码,用于演示如何在Go语言中使用指针。

英文:

You could use pointers, for example:

func main() {
	var jsonBlob = []byte(`[
		{"Name": "Platypus"},
		{"Name": "Quoll",    "Order": 100}
	]`)
	type Animal struct {
		Name  string 
		Order *int   
	}
	var animals []Animal
	err := json.Unmarshal(jsonBlob, &animals)
	if err != nil {
		fmt.Println("error:", err)
	}
	for _, a := range animals {
		if a.Order != nil {
			fmt.Printf("got order, %s : %d\n", a.Name, *a.Order)
		}
	}
}

答案2

得分: 0

我看不出你如何通过将struct传递给Unmarshal函数来实现这一点。例如,使用以下结构:

type A struct {
    Hello string
    Foo   int
    Baz   string
}
var a A
json.Unmarshal(data, &a)

即使通过另一种Unmarshal的实现,也只有两种(简单)的可能性:

  • 如果json数据中没有baz,将a.Baz设置为与其类型兼容的默认值,即空字符串(如果是整数则为0)。这是当前的实现方式。
  • 如果json数据中没有baz,返回一个错误。如果baz的缺失是正常行为,这将非常不方便。

另一种可能性是使用指针,并像我之前提到的默认值一样使用默认值nil,但如果你的json文件中可能填充了null值,仍然会有问题:你将无法区分json文件中设置为null的值和json中不存在的值,以及使用nil作为默认值进行解组的值。

然而,这个解决方案可能适合你:不使用struct,而是使用map[string]interface{}Unmarshal函数将不需要为不存在的字段添加默认值,并且可以从json文件中检索任何类型的数据。

var b = []byte(`[{"Name": "Platypus"}, {"Name": "Quoll", "Order": 100}]`)
var m []map[string]interface{}
err := json.Unmarshal(b, &m)
fmt.Println(m)
// [map[Name:Platypus] map[Name:Quoll Order:100]]
英文:

I don't see how you could do this by giving a struct to the Unmarshal function. With the following structure for instance:

type A struct {
    Hello string
    Foo   int
    Baz   string
}
var a A
json.Unmarshal(data, &a)

Even by doing another implementation of Unmarshal, there would be only two (simple) possibilities:

  • If baz is not in the json data, set a.Baz to a default value, compatible with its type: the empty string (or 0 if it's an integer). This is the current implementation.
  • If baz is not in the json data, return an error. That would be very inconvenient if the absence of baz is a normal behaviour.

Another possibility would be to use pointers, and use the default value nil in the same spirit than the default value I talked about, but there would still be issue if your json file could be filled with null values: you would not be able to distinguish values that were in the json file, but set as null, and values that were not in the json, and unmarshalled with nil as their default value.

However, this solution might suit you: instead of using a struct, why not using a map[string]interface{} ? The Unmarshall function would not have to add a default value to non-present fields, and it would be able to retrieve any type of data from the json file.

var b = []byte(`[{"Name": "Platypus"}, {"Name": "Quoll", "Order": 100}]`)
var m []map[string]interface{}
err := json.Unmarshal(b, &m)
fmt.Println(m)
// [map[Name:Platypus] map[Name:Quoll Order:100]]

huangapple
  • 本文由 发表于 2014年7月18日 04:28:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/24812933.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定