具有“有效”零值的解组JSON
我有一些JSON可以解构到各种结构中,这样我就可以处理数据,看起来这正在变成项目中最难的部分!具有“有效”零值的解组JSON
这个JSON的格式是,如果该字段丢失,那么它基本上是零。这是从Default struct values以下,但认为它值得它自己的问题上SO。
零因此是一个有效的值,我需要能够在我的Go代码中辨别出这个值。有没有办法使用指针去解组到这个结构?
在示例playground中,您可以看到我的意思,它“出现”可以工作,但是当我打印出其中一个指针值时,它总是打印指针地址而不是实际值。
package main
import "fmt"
import "log"
import "encoding/json"
const inputMissing = `
["AAAAAA", {"testCode" : "Sss"}, 123456]
`
const inputZero = `
["AAAAAA", {"testCode" : "Sss", "missingInt" : 0, "defaultInt" : 0,"missingString" : "", "defaultString" : ""}, 123456]
`
type RawMessage struct {
AlwaysString string
ClientData ClientData
ReceptionTime int
}
type ClientData struct {
TestCode string
MissingInt *int
DefaultInt int
MissingString *string
DefaultString string
}
func main() {
var n RawMessage
if err := json.Unmarshal([]byte(inputMissing), &n); err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", n)
var o RawMessage
if err := json.Unmarshal([]byte(inputZero), &o); err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", o)
fmt.Printf("Should print the value of the int, not pointer... %i", o.ClientData.MissingInt)
}
func (n *RawMessage) UnmarshalJSON(buf []byte) error {
tmp := []interface{}{&n.AlwaysString, &n.ClientData, &n.ReceptionTime}
wantLen := len(tmp)
if err := json.Unmarshal(buf, &tmp); err != nil {
return err
}
if g, e := len(tmp), wantLen; g != e {
return fmt.Errorf("wrong number of fields in RawMessage: %d != %d", g, e)
}
return nil
}
您的代码是正确的。测试对零和间接引用指针的指针,如果你想要的值:
fmt.Printf("Should print the value of the int, not pointer... %d", *o.ClientData.MissingInt)
对不起,我错过了!我现在觉得自己像个白痴! –
你不应该。没有这样的事情是一个愚蠢的问题。 –
谢谢!当使用指针而不是结构体中的值时,我是否必须小心内存泄漏,或者当我完成对象时,GC仍会踢入整个结构体? –
你的困惑源于fmt
包的默认格式,打印在指针字段的情况下,十六进制值,而不是尖锐的价值。
如果您正在使用%#v
动词进行打印,你可以实现你的结构来覆盖这个“行为”的fmt.GoStringer
接口:
func (c ClientData) GoString() string {
mi := "<missing>"
if c.MissingInt != nil {
mi = strconv.Itoa(*c.MissingInt)
}
ms := "<missing>"
if c.MissingString != nil {
ms = *c.MissingString
}
return fmt.Sprintf("{TestCode: %s, MissingInt: %s, DefaultInt: %d, MissingString: %s, DefaultString: %s}",
c.TestCode, mi, c.DefaultInt, ms, c.DefaultString)
}
和不断变化的最后的印刷线:
fmt.Printf("Should print the value of the int, not pointer... %d",
*o.ClientData.MissingInt)
你的输出变得更具有可读性(尝试在Go Playground):
main.RawMessage{AlwaysString:"AAAAAA", ClientData:{TestCode: Sss, MissingInt: <missing>, DefaultInt: 0, MissingString: <missing>, DefaultString: }, ReceptionTime:123456}
main.RawMessage{AlwaysString:"AAAAAA", ClientData:{TestCode: Sss, MissingInt: 0, DefaultInt: 0, MissingString: , DefaultString: }, ReceptionTime:123456}
Should print the value of the int, not pointer... 0
从上面的输出中可以看到,MissingXX
字段的静态值显示为<missing>
。
注:如果你使用%v
动词,你必须实现fmt.Stringer
接口,这基本上是一样的,只是方法名是不GoString()
而只是String()
。
非常感谢您花时间解释这一点。这非常有用。 –
我不明白。如果你需要这个值,你为什么不直接检查'nil'的指针然后解除引用呢? –
我不确定unmarshal是否正确设置值。无论我做什么,我都无法从'MissingInt'或'MissingString'读取0(或任何其他值) –
也许一个更好的例子是https://play.golang.org/p/RWKCFtlhMk,我不能打印/阅读555或测试 –