Video Coming Soon...
16: The Type System: Structs
WARNING This exercise is in DRAFT status, so there may be errors. If you find any, please email me at help@learncodethehardway.com so I can fix them.
From now on everything you'll learn about Go is some combination of--or is very similar to--something you already know. For example, Structs (the topic of this exercise) are nothing more than a collection of variables under one name. You alread know what a variable is, and how variables have a type (int, float32, etc.), so struct is nothing more than a grouping of those.
Another way to describe a struct is, "A new type that is a collection of other types." You can also think of a struct as a single row from a database or spreadsheet. Each column of the row has a name and a type (INTEGER, FLOAT, TEXT) and acts as a cohesive collection of those columns.
Using struct
Let's look at a small example:
type Position struct {
X int
Y int
}
Here we have a Position struct, and as you can see we create it with the type keyword. That identifies it as a new type similar to int or float32, but Position is composed of two fields (aka variables) X and Y.
This Position type can then be used as the type of a variable like so:
// declaring a variable as Position
var player_at Position
// or, with the := like so
enemy_at := Position{10,10}
To access the fields (contents) of the struct you use the . (dot) similar to how you use it with fmt.Println. The . (dot) usually means "get from" or "access" in many languages. For example, to get the position of an enemy I would do:
x_field := enemy_at.X
y_field := enemy_at.Y
Printing the coordinate would look something like this:
fmt.Println("x=", enemy_at.x, "y=", enemy_at.y)
Finally, you can set any field to a new value by simply treating it like a variable and use = (but not :=):
enemy_at.X = 100
enemy_at.Y = 20
The Code
Here's the code for this exercise, where we make some Animal structs and do things with the fields:
View Source file ex16/main.go Only
package main
import (
"fmt"
)
type Animal struct {
Name string
Age int
Species string
Weight float64
}
func PrintAnimal(who Animal) {
// you can pass your structs directly to Println
fmt.Println("Your Pet:", who)
}
func main() {
frankie := Animal{"Fankie", 5, "Dog", 20.5}
// access a field in a struct with .
fmt.Println("Name:", frankie.Name)
PrintAnimal(frankie)
// change a field by assigning to it
frankie.Weight = 25.6
fmt.Println("Your Pet Gained Weight:", frankie)
// make a copy of a struct
miss_snuffles := frankie
// test if they're equal
if(miss_snuffles == frankie) {
// change it with the . and =
miss_snuffles.Name = "Miss Snuffles"
miss_snuffles.Species = "Cat"
miss_snuffles.Weight = 4.0
}
// pass structs to functions
PrintAnimal(frankie)
PrintAnimal(miss_snuffles)
}
The Breakdown
As usual I'm only going to describe lines that are new to you.
type Animal struct {-- Create theAnimalstruct.Name string--Namefield of typestringAge int--Agefield of typeintSpecies string--Speciesfield of typestringWeight float64--Weightfield of typefloat64}-- Ends the structfunc PrintAnimal(who Animal) {-- Passing an animal to a function.frankie := Animal{"Fankie", 5, "Dog", 20.5};-- Create an animal that starts off withName="Frankie"and so on.fmt.Println("Name:", frankie.Name);-- Print theName.PrintAnimal(frankie)-- CallPrintAnimalwithfrankiefrankie.Weight = 25.6-- Changefrankie'sWeightto25.6fmt.Println("Your Pet Gained Weight:", frankie)-- Shamefrankiefor gaining weight.miss_snuffles := frankie-- Make a copy offrankie.if(miss_snuffles == frankie) {-- Test that two structs are equal.miss_snuffles.Name = "Miss Snuffles"-- Change this newAnimalto have different settings.miss_snuffles.Species = "Cat"-- It's a cat.miss_snuffles.Weight = 4.0-- Cats are small.PrintAnimal(frankie)-- Printfrankieagain.PrintAnimal(miss_snuffles)-- Printmiss_snuffles, so you can see how it changed.
Make sure you understand each line, and if there any you don't then try to figure out why. Sometimes experimenting with lines of code you don't get will help you understand it.
The Practice
- Break It -- Try assigning to fields with the wrong names, give them the wrong types (like try to set an
intto astring). - Change It -- Can you add to
Animal? Can you create anotherstruct? - Remake It -- As usual, write a description the recreate it from memory using the description. The more you do this, the better you'll get.
Study Drills
From now on I'm going to point you at the Go Specification and ask you to read it and try to understand it. You may not understand everything there, but it's good to know where it is.
- Read the Go Specification for
struct. - Add a struct that is inside the
Animalstruct as a new field. - Try using
fmt.Printlndirectly on thefrankievariable. - Using what you know about reading input from the last module, can you store a user's input into a
struct?
Register for Learn Go the Hard Way
Register today for the course and get the all currently available videos and lessons, plus all future modules for no extra charge.