2 回答
TA贡献1828条经验 获得超6个赞
JSON 是一个数组,因此您需要将一个数组传递给 Decode 方法。还记得检查返回的错误。
package main
import(
"encoding/json"
"net/http"
"log"
)
type CoinMarketCapData struct {
Id string
Name string
Symbol string
Rank int
PriceUSD float64
PriceBTC float64
Volume24hUSD float64
MarketCapUSD float64
AvailableSupply float64
TotalSupply float64
PercentChange1h float32
PercentChange24h float32
PercentChange7d float32
}
func getJson(url string, target interface{}) error {
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Content-Type", "application/json")
r, err := client.Do(req)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func main() {
//Test with CoinMarketCap JSON
url2 := "https://api.coinmarketcap.com/v1/ticker/ethereum"
priceData := make([]CoinMarketCapData, 0)
err := getJson(url2, &priceData)
if err != nil {
log.Printf("Failed to decode json: %v", err)
} else {
//Should print "Ethereum Id: ethereum"
log.Printf("Ethereum Id: %v", priceData[0].Id)
}
}
运行此打印
2016/08/21 17:15:27 Ethereum Id: ethereum
TA贡献1799条经验 获得超6个赞
你是对的,顶级 API 响应类型是一个列表,它必须反映在解组过程中。解决此问题的一种方法是将您的MarketCap响应定义为切片,如下所示:
package main
import (
"encoding/json"
"log"
"net/http"
)
// curl -sLf "https://api.coinmarketcap.com/v1/ticker/ethereum" | JSONGen
// command line helper: `go get github.com/bemasher/JSONGen`
type MarketCapResponse []struct {
AvailableSupply float64 `json:"available_supply"`
HVolumeUsd float64 `json:"24h_volume_usd"`
Id string `json:"id"`
MarketCapUsd float64 `json:"market_cap_usd"`
Name string `json:"name"`
PercentChange1h float64 `json:"percent_change_1h"`
PercentChange24h float64 `json:"percent_change_24h"`
PercentChange7d float64 `json:"percent_change_7d"`
PriceBtc float64 `json:"price_btc"`
PriceUsd float64 `json:"price_usd"`
Rank int64 `json:"rank"`
Symbol string `json:"symbol"`
TotalSupply float64 `json:"total_supply"`
}
然后解组就可以正常工作了。需要注意的一点是指向切片的指针与切片不同。特别是指针不支持索引,这就是为什么需要先取消引用才能访问列表中的第一项。
func getAndUnmarshal(url string, target interface{}) error {
var client = &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Content-Type", "application/json")
r, _ := client.Do(req)
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func main() {
link := "https://api.coinmarketcap.com/v1/ticker/ethereum"
resp := new(MarketCapResponse)
getAndUnmarshal(link, resp)
log.Printf("Ethereum Id: %s", (*resp)[0].Id)
// prints:
// 2016/08/22 02:13:23 Ethereum Id: ethereum
}
另一种方法是为单个MarketCap定义一个类型,然后在需要时创建一个切片作为目标:
package main
// curl -sLf "https://api.coinmarketcap.com/v1/ticker/ethereum" | jq .[0] | JSONGen
type MarketCap struct {
AvailableSupply float64 `json:"available_supply"`
HVolumeUsd float64 `json:"24h_volume_usd"`
Id string `json:"id"`
MarketCapUsd float64 `json:"market_cap_usd"`
Name string `json:"name"`
PercentChange1h float64 `json:"percent_change_1h"`
PercentChange24h float64 `json:"percent_change_24h"`
PercentChange7d float64 `json:"percent_change_7d"`
PriceBtc float64 `json:"price_btc"`
PriceUsd float64 `json:"price_usd"`
Rank int64 `json:"rank"`
Symbol string `json:"symbol"`
TotalSupply float64 `json:"total_supply"`
}
func getAndUnmarshal(url string, target interface{}) error {
...
}
func main() {
link := "https://api.coinmarketcap.com/v1/ticker/ethereum"
resp := make([]MarketCap, 0)
getAndUnmarshal(link, &resp)
log.Printf("Ethereum Id: %s", resp[0].Id)
// 2016/08/22 02:13:23 Ethereum Id: ethereum
}
什么更适合您将取决于您的用例。如果您希望结构反映 API 响应,那么第一种方法似乎更合适。MarketCap是一件事吗?我相信,API 只是访问它的一种方式,比第二种方式更合适。
- 2 回答
- 0 关注
- 186 浏览
添加回答
举报