使用了太長時間的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