{ "test": 1, "key": { "k1": "1", "k2": 2 } }但是key 结构体下面是未知的。可能是K1 K2 K3 … KN。如何解析传递那?
type Data struct { Test int `json:"test"` Key map[string]interface{} `json:"test"` }但问题是,这种方式太坑,每次从 key 中拿数据,都要做类型检查,判断是否 ok。
{ "type": "UPDATE", "database": "blog", "table": "blog", "data": [ { "blogId": "100001", "title": "title", "content": "this is a blog", "uid": "1000012", "state": "1" } ] }简单说下数据的逻辑,type 表示数据库事件是新增、更新还是删除事件,database 表示对应的数据库名称,table 表示相应的表名称,data 即为数据库中数据。怎么处理这串 JSON 呢?
func main () { msg := []byte(`{ "type": "UPDATE", "database": "blog", "table": "blog", "data": [ { "blogId": "100001", "title": "title", "content": "this is a blog", "uid": "1000012", "state": "1" } ]}`) var event map[string]interface{} if err := json.Unmarshal(msg, &event); err != nil { panic(err) } // 堆代码 duidaima.com fmt.Println(event) }打印结果如下:
map[data:[map[title:title content:this is a blog uid:1000012 state:1 blogId:100001]] type:UPDATE database:blog table:blog]到此,就成功解析出了数据。接下来是使用它,但我觉得 map 通常有几个不足。
2.相对于结构体的方式,map数据提取不便且不能利用 IDE 补全检查,key 容易写错;
type Event struct { Type string `json:"type"` Database string `json:"database"` Table string `json:"table"` Data []map[string]string `json:"data"` }说明几点:
e := Event{} if err := json.Unmarshal(msg, &e); err != nil { panic(err) } fmt.Println(e)打印结果:
{UPDATE blog blog [map[blogId:100001 title:title content:this is a blog uid:1000012 state:1]]}接下来,数据的使用就方便了不少,比如事件类型获取,通过 event.Type 即可完成。不过,要泼盆冷水,因为 data 还是 []map[string]string 类型,依然有 map 的那些问题。能不能把 map 转化为 struct ?
$ go get https://github.com/mitchellh/mapstructure开始使用前,先定义 map 将转化的 struct 结构,即 blog 结构体,如下:
type Blog struct { BlogId string `mapstructure:"blogId"` Title string `mapstructrue:"title"` Content string `mapstructure:"content"` Uid string `mapstructure:"uid"` State string `mapstructure:"state"` }因为,接下来要用的是 mapstructure 包,所以 struct tag 标识不再是 json,而是 mapstructure。
e := Event{} if err := json.Unmarshal(msg, &e); err != nil { panic(err) } if e.Table == "blog" { var blogs []Blog if err := mapstructure.Decode(e.Data, &blogs); err != nil { panic(err) } fmt.Println(blogs) }event 的解析和前面的一样,通过 e.Table 判断是是否来自 blog 表的数据,如果是,使用 Blog 结构体解析。接下来通过 mapstructure 的 Decode 完成解析。
[{100001 title this is a blog 1000012 1}]到此,似乎已经完成了所有工作。非也!
type Blog struct { BlogId string `mapstructure:"blogId"` Title string `mapstructrue:"title"` Content string `mapstructure:"content"` Uid int32 `mapstructure:"uid"` State int32 `mapstructure:"state"` }但是当把新的 Blog 类型代入之前的代码,会如下的错误。
panic: 2 error(s) decoding: * '[0].state' expected type 'int32', got unconvertible type 'string' * '[0].uid' expected type 'int32', got unconvertible type 'string'提示类型解析失败。其实,这种形式的 json 在其他一些软类型语言中也会出现。
2.使用 mapstructure 提供的软类型 map 转化 struct 的功能;
var blogs []Blog if err := mapstructure.WeakDecode(e.Data, &blogs); err != nil { panic(err) } fmt.Println(blogs)其实只需要把 mapstructure 的 Decode 替换成 WeakDecode 就行了,字如其意,弱解析。如此easy。到此,才算完成!接下来的数据处理就简单很多了。如果想学习 mapstructure 的使用,敲敲源码中例子应该差不多了。