使用Golang进行JSON解码
最近我在学习Golang,一边通过搜索了解相关知识,一边尝试阅读JSON和Go的文档来实践。
{
"period": "yy",
"exec_period": {
"start": {
"month": 1,
"week": 2,
"day": 3,
"hour": 4,
"minute": 5
},
"end": {
"month": 6,
"week": 7,
"day": 8,
"hour": 9,
"minute": 10
}
},
"backup": [
{
"local_dir": "directoryLo1",
"server_dir": "directoryLo2",
"server_host": "domaineName"
},
{
"local_dir": "directoryLo1",
"server_dir": "directorySe2",
"server_host": "domaineName"
}
],
"incremental_save": "1Y2M"
}
假设有这样一个JSON数据。
可以使用标准库encoding/json来读取它,写成类似这样的代码。
package main
import (
"encoding/json"
"fmt"
"os"
)
type time struct {
Month int
Week int
Day int
Hour int
Minute int
}
type execPeriod struct {
Start time
End time
}
type directories struct {
LocalDir string `json:"local_dir"`
ServerDir string `json:"server_dir"`
ServerHost string `json:"server_host"`
}
type data struct {
Period string
ExecPeriod execPeriod `json:"exec_period"`
Backup []directories
IncrementalSave string `json:"incremental_save"`
}
func main() {
dec := json.NewDecoder(os.Stdin)
var d data
dec.Decode(&d)
fmt.Printf("%+v\n", d)
}
$ ./json < test.json
{Period:yy ExecPeriod:{Start:{Month:1 Week:2 Day:3 Hour:4 Minute:5} End:{Month:6 Week:7 Day:8 Hour:9 Minute:10}} Backup:[{LocalDir:directoryLo1 ServerDir:directoryLo2 ServerHost:domaineName} {LocalDir:directoryLo1 ServerDir:directorySe2 ServerHost:domaineName}] IncrementalSave:1Y2M}
只要像json一样定义结构体,并将其传递给json.Decoder,就可以了解情况。但是,如果键的名称与json不同,则需要用json:”key_name”这样的方式来弥补差异。
在JSON和Go的后面,还介绍了在不了解JSON结构的情况下的处理方法,建议使用interface!由于对interface不太了解,我在查找资料的同时进行了以下操作。
package main
import (
"encoding/json"
"fmt"
"os"
)
func assert(data interface{}) {
switch data.(type) {
case string:
fmt.Print(data.(string))
case float64:
fmt.Print(data.(float64))
case bool:
fmt.Print(data.(bool))
case nil:
fmt.Print("null")
case []interface{}:
fmt.Print("[")
for _, v := range data.([]interface{}) {
assert(v)
fmt.Print(" ")
}
fmt.Print("]")
case map[string]interface{}:
fmt.Print("{")
for k, v := range data.(map[string]interface{}) {
fmt.Print(k + ":")
assert(v)
fmt.Print(" ")
}
fmt.Print("}")
default:
}
}
func main() {
var data interface{}
dec := json.NewDecoder(os.Stdin)
dec.Decode(&data)
assert(data)
fmt.Println()
}
$ ./json < test.json
{period:yy exec_period:{start:{month:1 week:2 day:3 hour:4 minute:5 } end:{month:6 week:7 day:8 hour:9 minute:10 } } backup:[{local_dir:directoryLo1 server_dir:directoryLo2 server_host:domaineName } {local_dir:directoryLo1 server_dir:directorySe2 server_host:domaineName } ] incremental_save:1Y2M nulltest:null }
界面太厉害了。
该示例与《Effective Go》中的类型切换完全一样,可以根据类型断言的结果来分配处理。根据这里的解释,Decode的结果应该是bool、float64、string、[]interface{}、map[string]interface{}、nil中的一种,因此先用interface{}接收,然后根据各自的情况来进行相应的处理。
实际使用时,我觉得定义struct会更方便后续使用,但是golang的interface除了这个,还有很多其他的功能,看起来很有趣。