Skip to content

Instantly share code, notes, and snippets.

@dacort
Forked from mattyw/multiple_types.go
Last active November 15, 2018 12:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dacort/4560701 to your computer and use it in GitHub Desktop.
Save dacort/4560701 to your computer and use it in GitHub Desktop.
package main
import (
"encoding/json"
"fmt"
)
var jsonStr = []byte(`
{
"things": [
{
"name": "Alice",
"age": 37
},
{
"city": "Ipoh",
"country": "Malaysia"
},
{
"name": "Bob",
"age": 36
},
{
"city": "Northampton",
"country": "England"
}
]
}`)
func main() {
personsA, placesA := solutionA(jsonStr)
fmt.Printf("%d %d\n", len(personsA), len(placesA))
personsB, placesB := solutionB(jsonStr)
fmt.Printf("%d %d\n", len(personsB), len(placesB))
personsC, placesC := solutionC(jsonStr)
fmt.Printf("%d %d\n", len(personsC), len(placesC))
}
//Common to both solutions
type Person struct {
Name string
Age int
}
type Place struct {
City string
Country string
}
//Generic incoming message
type Thing struct {
Person *Person
Place *Place
}
type IncomingMessage struct {
Things []Thing
}
func (t *Thing) UnmarshalJSON(incoming []byte) error {
var data map[string]interface{}
err := json.Unmarshal(incoming, &data)
if err != nil {
return err
}
if data["name"] != nil {
t.Person = &Person{data["name"].(string), int(data["age"].(float64))}
// return nil // Person{data["name"].(string), data["age"].(int)}
} else {
t.Place = &Place{data["city"].(string), data["country"].(string)}
}
return nil
}
//Solution A
//Unmarshal into a map
//Type assert when we need it
func solutionA(jsonStr []byte) ([]Person, []Place) {
persons := []Person{}
places := []Place{}
var data map[string][]map[string]interface{}
err := json.Unmarshal(jsonStr, &data)
if err != nil {
fmt.Println(err)
return persons, places
}
for i := range data["things"] {
item := data["things"][i]
if item["name"] != nil {
persons = addPerson(persons, item)
} else {
places = addPlace(places, item)
}
}
return persons, places
}
func addPerson(persons []Person, item map[string]interface{}) []Person {
name, _ := item["name"].(string)
age, _ := item["age"].(int)
person := Person{name, age}
persons = append(persons, person)
return persons
}
func addPlace(places []Place, item map[string]interface{}) []Place {
city, _ := item["city"].(string)
country, _ := item["city"].(string)
place := Place{city, country}
places = append(places, place)
return places
}
//SolutionB
type Mixed struct {
Name string `json:"name"`
Age int `json:"age"`
City string `json:"city"`
Country string `json:"country"`
}
func solutionB(jsonStr []byte) ([]Person, []Place) {
persons := []Person{}
places := []Place{}
var data map[string][]Mixed
err := json.Unmarshal(jsonStr, &data)
if err != nil {
fmt.Println(err)
return persons, places
}
for i := range data["things"] {
item := data["things"][i]
if item.Name != "" {
persons = append(persons, Person{item.Name, item.Age})
} else {
places = append(places, Place{item.City, item.Country})
}
}
return persons, places
}
//SolutionC
func solutionC(jsonStr []byte) ([]Person, []Place) {
persons := []Person{}
places := []Place{}
var data IncomingMessage
err := json.Unmarshal(jsonStr, &data)
if err != nil {
fmt.Println(err)
return persons, places
}
for _, thing := range data.Things {
if thing.Person != nil {
persons = append(persons, *thing.Person)
} else if thing.Place != nil {
places = append(places, *thing.Place)
}
}
return persons, places
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment