Imagine that you are an avid cat enthusiast and that you desire a piece of software to manage your cat(s) and their daily lives. This exercise can be easily performed if you have a single cat:
package main import "fmt" func main() { var name string = "Mr. Tinkle" var age int = 6 fmt.Printf("%v - %v", name, age) }
Simple stuff, right? But what if we have two cats? A lazy solution would be to add more variables called ‘name2’ and ‘age2’. What about three cats or four? What if we foster cats and we are constantly adding and removing cats?
Adding variable names and rebuilding our program constantly isn’t a very stable solution, and we would be spending more time with our computer than our cats.
Ok, let’s try something else. Let’s make an array of all our names and another one for all our ages.
package main import "fmt" func main() { var names [3]string var ages [3]int names[0] = "Mr Tinkle" ages[0] = 6 names[1] = "Mittens" ages[1] = 2 names[2] = "Admiral Fluffybottom" ages[2] = 10 for j := 0 ; j < 3; j++ { fmt.Printf("%v - %v", names[j], ages[j]) } }
Now we only have two variables: name, and age. But we have a new problem — the ages have no relation to the names other than an index number that we have to remember. if the name array and age array ever become misaligned then our entire dataset is ruined and lost. The solution is to create a custom variable type called “Cat” that can store both variables together. So let’s just get on the phone with the folks who made the go language and have them add a custom type to the language…
… they laughed and hung up, but it seems that language was designed with this need in mind. Structs are a construct built into go that allow us to create and manage custom types. And here’s how:
package main import "fmt" type Cat struct{ name string age int } func main() { var cats [3]Cat cats[0] = Cat{"Mr Tinkle", 6} cats[1] = Cat{"Mittens", 2} cats[2] = Cat{"Admiral FluffyBottom", 10} //changing information about our cats is easier name cats[3].age = 11 //happy birthday Mr FluffyBottom for j := 0 ; j < 3; j++ { fmt.Printf("%v - %v", cats[j].name, cats[j].age) } }
The magic happens on lines 5-8. We tell go that we are going to create a custom type called “Cat” and that it will be a struct. Over the next few lines, we then lay out the members of our struct. Namely, two variables, a string called name, and an integer called age. This tells go that every time it sees the variable type “Cat” it will internally have these two elements. Those elements are still independently accessible as shown on lines 18 and 21 using a period/dot “.” but they can never become detached from each other. This allows us to pass cats to functions, and store them in more flexible ways without ever worrying about our data becoming corrupt.
Next time we will take a look at how to pass our Cats around from one function to another, as well as how to ensure that we don’t accidentally clone our cats!