与Golang中的结构数组混淆

I am trying to interact with a JSON API. It has two endpoints:

GetTravelTimeAsJSON - specify a traveltime ID and it returns a single traveltime GetTravelTimesAsJSON - returns an array with all the above TravelTimes.

So I have a struct like so:

type TravelTime struct {
  AverageTime int     `json:"AverageTime"`
  CurrentTime int     `json:"CurrentTime"`
  Description string  `json:"Description"`
  Distance    float64 `json:"Distance"`
  EndPoint    struct {
    Description string  `json:"Description"`
    Direction   string  `json:"Direction"`
    Latitude    float64 `json:"Latitude"`
    Longitude   float64 `json:"Longitude"`
    MilePost    float64 `json:"MilePost"`
    RoadName    string  `json:"RoadName"`
  } `json:"EndPoint"`
  Name       string `json:"Name"`
  StartPoint struct {
    Description string  `json:"Description"`
    Direction   string  `json:"Direction"`
    Latitude    float64 `json:"Latitude"`
    Longitude   float64 `json:"Longitude"`
    MilePost    float64 `json:"MilePost"`
    RoadName    string  `json:"RoadName"`
  } `json:"StartPoint"`
  TimeUpdated  string `json:"TimeUpdated"`
  TravelTimeID int    `json:"TravelTimeID"`
}

If I call the API like so for a single travel time, I get a populated struct (I'm using this req lib)

header := req.Header{
    "Accept":          "application/json",
    "Accept-Encoding": "gzip",
  }
  r, _ := req.Get("http://www.wsdot.com/Traffic/api/TravelTimes/TravelTimesREST.svc/GetTravelTimeAsJson?AccessCode=<redacted>&TravelTimeID=403", header)
  var foo TravelTime

  r.ToJSON(&foo)
  dump.Dump(foo)

If I dump the response, it looks like this:

TravelTime {
  AverageTime: 14 (int),
  CurrentTime: 14 (int),
  Description: "SB I-5 Pierce King County Line To SR 512",
  Distance: 12.06 (float64),
  EndPoint:  {
    Description: "I-5 @ SR 512 in Lakewood",
    Direction: "S",
    Latitude: 47.16158351 (float64),
    Longitude: -122.481133 (float64),
    MilePost: 127.35 (float64),
    RoadName: "I-5"
  },
  Name: "SB I-5, PKCL To SR 512",
  StartPoint:  {
    Description: "I-5 @ Pierce King County Line",
    Direction: "S",
    Latitude: 47.255624 (float64),
    Longitude: -122.33113 (float64),
    MilePost: 139.41 (float64),
    RoadName: "I-5"
  },
  TimeUpdated: "/Date(1532707200000-0700)/",
  TravelTimeID: 403 (int)
}

Now, what I want to do is have a struct for ALL responses, which is a slice of the TravelTime struct, so I did this:

type TravelTimesResponse struct {
  TravelTime []TravelTime
}

However, when I call the GetTravelTimesAsJSON endpoint, and change it so:

var foo TravelTimesResponse

I get back 180 (the number of results) empty sets like this:

{
    TravelTime: TravelTime {
      AverageTime: 0 (int),
      CurrentTime: 0 (int),
      Description: "",
      Distance: 0 (float64),
      EndPoint:  {
        Description: "",
        Direction: "",
        Latitude: 0 (float64),
        Longitude: 0 (float64),
        MilePost: 0 (float64),
        RoadName: ""
      },
      Name: "",
      StartPoint:  {
        Description: "",
        Direction: "",
        Latitude: 0 (float64),
        Longitude: 0 (float64),
        MilePost: 0 (float64),
        RoadName: ""
      },
      TimeUpdated: "",
      TravelTimeID: 0 (int)
    }

The JSON is here: https://gist.github.com/jaxxstorm/0ab818b300f65cf3a46cc01dbc35bf60

It works if I modify the original TravelTime struct to be a slice like so:

type TravelTimes []struct {

}

but then it doesn't work as a single response.

I've managed to do this before, but for some reason the reason this failing is failing my brain. Any help appreciated.

Change the struct TravelTimesResponse field name TravelTime which is similar to the struct name TravelTime and then try to unmarshal the JSON.

type TravelTimesResponse struct {
  TravelTime []TravelTime
}

Above should have different field name as:

type TravelTimesResponse struct {
  TravelTimeData []TravelTime
}

[Edited]

The library is using interface{} directly to unmarshal the response

// ToJSON convert json response body to struct or map
func (r *Resp) ToJSON(v interface{}) error {
    data, err := r.ToBytes()
    if err != nil {
        return err
    }
    return json.Unmarshal(data, v)
}

Given JSON is an array of objects. And you are parsing it to struct with field name which will be an object key. Either create a slice of struct or implement unmarshal.

Unmarshal stores one of these in the interface value:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

Better is to use Go package for encoding/json.

Try Working Code on Go playground

The unmarshal isn't working because it's expecting the top level to be an object with a field TravelTime, when the top level is actually the array of objects. You just want to unmarshal directly into a slice of objects, like so:

  var foo []TravelTime

  r.ToJSON(&foo)