Golang的Json encode/decode以及[]byte和string的转换
使用了太长时间的python,对于强类型的Golang适应起来稍微有点费力,不过操作一次之后发现,只有这么严格的类型规定,才能让数据尽量减少在传输和解析过程中的错误。我尝试使用Golang创建了一个公司的OpenAPI的demo,记录一下中间遇到的问题。
编码(Encode)Json:
首先来看下如何将字典编码成Json:
// 首先使用字面量来申明和初始化一个字典 param := map[string]int{"page_no": 1, "page_size": 40} paramJson, err := json.Marshal(param)
使用json.Marshal接收需要json.encode的变量。而json.Marshal接收的是interface{}接口变量,该接口变量可以接收任何类型的数据。
[]byte转String以及String转[]byte:
通常我在python里面使用json.dumps来对字典进行序列化的时候,我通常认为出来的值是一个string,可以将其作为string进行操作。但是这里很明显返回的不是字符串(string)类型,而是一个[]byte类型。所以如果有需要,我们可以将[]byte类型,转换回string进行操作。这里有几种方法可供选择:
直接使用:
string([]byte)
或使用:
String([]byte[:])
ps:现在这两个得到的结果会是一样的,我现在使用的版本是1.8。1.8以前好像会是不同的表现。
同时我们也会遇到想要将string转换回[]byte的时候。方法如下:
[]byte(string)
Http包的post请求来实践对Json的序列化反序列化:
当我们把json编码好之后我们需要将信息传递给服务器。所以用到了http包。
在使用了之后我觉得go的http包真的非常方便,的确如传言中描述的强大和人性化,方便实用。
resp , err := http.PostForm(requestUrl, url.Values{"api_key": {ApiKey}, "api_sign": {apiSign}, "param": {string(param)}, "time": {now_time}, "version": {version}})
这里我使用http.PostForm方法使用带参数传递的post方法请求服务器。url.Values后面可以跟key[string][]string的形式传递参数。返回一个http.response结构体指针和一个error类型。
http.response具体带有哪些属性可以详细查看一下包,这里我们会去解析他的Body字段,里面存储着返回的内容:
// The Body is automatically dechunked if the server replied // with a "chunked" Transfer-Encoding. Body io.ReadCloser
这里Body是一个有io.ReadCloser接口的值。io.ReadCloser接口实现了Read()和Write()方法。
我会用json的Decoder去解析它:
var response openApiResponse resp := request.RequestHeader(paramJson, version, SyncUrl) err1 := json.NewDecoder(resp.Body).Decode(&response) if err1 != nil { log.Println(err1) }
return resp
这里json.NewDecoder接收一个有Reader方法的变量,之后我们调用了Decoder的方法decode将里面的内容都存入事先申请好的response结构体变量中。这个变量初始化了我们通过文档了解到的返回的结构体字段类型。
openApiResponse struct { Success bool `json:"success"` ResultCode int `json:"result_code"` ResultMsg string `json:"result_msg"` // 接收JSON字段 Result GoodsSyncResult `json:"result"` }
这样一级一级解析下去,在构造接收返回回来数据的结构体的时候,注意到后面的json字段。他是一个tag,可以在解析json的时候将对应名字的tag解析到对应的变量中。
这样就相当于你做好了数据结构,然后将对应的数据放到对应的字段里面去。
当然还有一种办法,当你不知道你所接收数据的数据结构的时候,你是没有办法提前申明好这些数据结构然后来接收的。这时我们可以申明一个空接口interface{},让空接口的指针来接收这组数据,可以查看这组数据的数据结构。
var hahaha interface{} resp := request.RequestHeader(paramJson, version, SyncUrl) err1 := json.NewDecoder(resp.Body).Decode(&hahaha) if err1 != nil { log.Println(err1) }
上面的hahaha可以接收并decodejson,来接收这组数据。并且可以直接使用fmt.Print之类函数直接打印接收到的数据。如果想直接使用,我们可以使用类型断言但是更推荐的方法是,我们可以根据这组数据来写对应的结构体,然后将数据接收到结构体上进行操作。就像上面一样。
同样的我们还可以使用一个map[string]interface{}来接收这个Json以方便对其进行后续操作,避免不需要的多余的反射。
var hahaha map[string]interface{} resp := request.RequestHeader(paramJson, version, SyncUrl) err1 := json.NewDecoder(resp.Body).Decode(&hahaha) return hahaha
除了实现一个decoder来处理数据,我们往往有Json序列化之后就立即需要序列化的操作,这个同样很容易使用:
json.Unmarshal([]byte, &xx)
来处理就好了。参数一是需要decode的Json数据, 参数二是用于接收这组数据的结构体字段。同样的我们也可以使用一个空接口来接收数据,也可以使用一一对应的结构体来放置数据。
看了上面的一堆介绍有一个感觉,就处理Json数据和类型转换来说。。python真是简单到爆炸,一个dumps一个loads轻松搞定。但是Golang严格的参数类型缺可以保证解析过来的数据一定是对应的数据结构和数据类型。不会在类型上报错更为严谨。个人觉得这很有趣,也很喜欢。
Reference:
http://stackoverflow.com/questions/3371714/go-string-to-ascii-byte-array go-string-to-ascii-byte-array
http://stackoverflow.com/questions/24377907/golang-issue-with-accessing-nested-json-array-after-unmarshalling golang-issue-with-accessing-nested-json-array-after-unmarshalling
http://blog.csdn.net/tiaotiaoyly/article/details/38942311 在Go语言中使用JSON