What Are Golang’s Anonymous Structs?

An anonymous struct is just like a normal struct, but it’s defined without a name, and as such can’t be referenced elsewhere in code. Structs in Go are similar to structs in other languages like C. They have typed collections of fields, and are used to group data together in order to make it more manageable by us as programmers.

Sorry to interrupt! I just wanted to mention that you should check out my new free Go course. It’s designed to teach you all the fundamentals of my favorite coding language.

To create an anonymous struct, just instantiate the instance immediately after declaring the type:

newCar := struct { make string model string mileage int }{ make: "Ford", model: "Taurus", mileage: 200000, }
Code language: Go (go)

Contrast this with the “normal” way of creating structs:

// declare the 'car' struct type type car struct { make string model string mileage int } // create an instance of a car newCar := car{ make: "Ford", model: "taurus", mileage: 200000, }
Code language: Go (go)

When should I use an anonymous struct?

I often use anonymous structs to marshal and unmarshal JSON data in HTTP handlers. If a struct is only meant to be used once, then it makes sense to declare it in such a way that developers down the road won’t be tempted to accidentally use it again.

Take a look at the code below. We are able to marshal the HTTP request directly into a newCar struct without ever giving the struct a name. All the fields are still accessible via the dot operator, but we don’t have to worry about another part of our project trying to use a type that wasn’t intended for it.

func createCarHandler(w http.ResponseWriter, req *http.Request) { defer req.Body.Close() decoder := json.NewDecoder(req.Body) newCar := struct { Make string `json:"make"` Model string `json:"model"` Mileage int `json:"mileage"` }{} err := decoder.Decode(&newCar) if err != nil { log.Println(err) return } makeCar(newCar.Make, newCar.Model, newCar.Mileage) return }
Code language: Go (go)

Don’t use map[string]interface{} for JSON data if you can avoid it.

Instead of declaring a quick anonymous struct for JSON unmarshalling, I’ve often seen map[string]interface{} used. This is terrible in most scenarios for several reasons:

  1. No type checking. If the client sends a key called “model” as a bool, but it was supposed to be a string, then unmarshalling into a map won’t catch the error
  2. Maps are vague. After unmarshalling the data, we are forced to use runtime checks to make sure the data we care about exists. If those checks aren’t thorough, it can lead to a nil pointer dereference panic being thrown.
  3. map[string]interface{} is verbose. Digging into the map isn’t as simple as accessing a named field using a dot operator, for example, newCar.model. Instead, its something like:
func createCarHandler(w http.ResponseWriter, req *http.Request) { myMap := map[string]interface{}{} decoder := json.NewDecoder(req.Body) err := decoder.Decode(&myMap) if err != nil { log.Println(err) return } model, ok := myMap["model"] if !ok { fmt.Println("field doesn't exist") return } modelString, ok := model.(string) if !ok { fmt.Println("model is not a string") } // do something with model field }
Code language: Go (go)

Anonymous structs can clean up your API handlers if used properly. The strong typing they offer while still being a “one-off” solution is a powerful tool.

Have questions or feedback?

Follow and hit me up on Twitter @q_vault if you have any questions or comments. If I’ve made a mistake in the article be sure to let me know so I can get it corrected!

Related Articles