Golang — json Unmarshal 轉換碰上type interface {} does not support indexing

ss
4 min readFeb 4, 2019

--

最近在無聊, 在寫line chat bot, 在接收來自line的event, line會用HTTP POST送到你預先設定的web server, 送的格式為json

在學生時候我很喜歡golang 這語言, 但由於在工作的時候都是使用python, 或是C++(幾乎都是為了效能), 用過python寫web的都知道, 幾乎是最輕鬆的語言沒有之一, 但是在效能上還是有考慮的部分, 在這邊我們就不深入探討, 而這次我在寫web server時使用的是golang的 gin 這個framework, 一個輕便且高效的framwork, 但是在撰寫的部分有時候真的也不像python 那麼得輕鬆, 而我在這邊就遇到一個讀去json的問題

我們都知道python 能輕鬆的將json 轉換成dict的方式, 讓你輕鬆做存取, 但golang在轉換的過程可就沒有這麼順利了, golang轉換json大致上分成兩種

一種是你了解傳送過來json的結構, 利用type struct 去定義好之後再進行讀取

故另一種方式就是利用 map[string]interface{}, 將json 利用json.Unmarshal

ex:

package mainimport (
"encoding/json"
"fmt"
)
func main() {
var result map[string]interface{}
json_body := []byte(`{"a":92, "b":[{"c": 123, "d": 1235}]}`)
json.Unmarshal(json_body, &result)
fmt.Println(result)
}

這邊印出的結果會是

map[a:92 b:[map[c:123 d:1235]]]

假設我想要取得b的值map[c:123 d:1235]]

我可以利用 result[“b”]來幫助我完成

package mainimport (
"encoding/json"
"fmt"
)
func main() {
var result map[string]interface{}
json_body := []byte(`{"a":92, "b":[{"c": 123, "d": 1235}]}`)
json.Unmarshal(json_body, &result)
fmt.Println(result)
fmt.Println("============")
fmt.Println(result["b"])
}

結果

map[a:92 b:[map[d:1235 c:123]]]
============
[map[c:123 d:1235]]

然而, 若我想進一步取得b裡頭的c值的時候 我們是否能如法炮製用result[“b”][“c”]呢

直接使用會得到一個訊息

type interface {} does not support indexing

為什麼不能這樣用? b裡面存的明明就是一個list(slice)

這邊比較特別的是因為我們的result 是負責mapping [string -> interface{}], 在這邊b的value 為 interface{}.

然而interface{} 並不屬於slice, 故我們無法直接這樣使用, 那我們該如何取得呢

我們可以使用reflect這個函式庫, 它幫助我們可以取得這個interface裡的直並幫助轉換, 將剛剛的程式碼改成以下

package mainimport (
"encoding/json"
"fmt"
"reflect"
)
func main() {
var result map[string]interface{}
json_body := []byte(`{"a":92, "b":[{"c": 123, "d": 1235}]}`)
json.Unmarshal(json_body, &result)
fmt.Println(result)
fmt.Println("============")
fmt.Println("b", result["b"])
fmt.Println("============")
value := reflect.ValueOf(result["b"])
c := value.Index(0).Interface().(map[string]interface{})
fmt.Println("c", c)
}

這樣便可以順利的去將c轉換成interface{}, 並且輸出, 當然這樣的方式有點土法煉鋼, 我們也不大可能一直這樣try下去, 故還是得事先了解json的結構利用type struct下去寫會比較合理些

歡迎糾正或討論

--

--