Hi everyone! this is Jimmy , and this is the third article in my series “Breaking Things with Go.” In this series, I document my journey through Jon Bodner’s Second Edition: Learning Go – An Idiomatic Approach to Real-World Go Programming and explore how to use Go in the most practical way I can
in this series the resources are the book itself, go documentation, and any AI model to clarify some things
lets Jump into it

in the last Break we dived a little bit into Composite types and talked about Slices
but there is some situations where we will need to give each value a key at storing (for example to facilitate the searching process later by searching for that key instead of iterating over the entire slice by index) that’s where Maps come in handy
It is recommended to look at this video before reading this break here
Introduction to Maps
built-in data structure for situation where you want to associate one value to another map[keyType]valueType
first way to declare
var nilMap map[string]int
the zero value for a map is nil and its length is zero you can read values from nil and it will return zero value of the type
fmt.Println(nilMap["a"]) //0 cause values has the type int
but you can't write to nil map it will cause panic
other way to declare map is by using map literal
totalWins := map[string]int{}
this is an empty map not a nil map so you can read and write to it
you can also assign non-empty map literal
teams := map[string][]string{
"lakers": []string{"luka", "lebron", "smart_is_dumb"},
"states": []string{"steph", "green"},
"bucks": {"anteto"}, // you don't have to specify the value type cause it is already known in the declaration
}
so as you can see it is written like dictionaries in Python but you have to separate each line with a comma even the last line
you can always use make
ages := make(map[int][]string, 10)
this is also a 0 length map that can grow past the initially specified size
maps and slices has similar properties:
- maps also grow automatically by adding more pairs
- you can use make to create map if you know how many pairs you will insert into the map
- passing map to
lentells you how many pairs are in it - zero value for a map is
nil - maps are only comparable with
nilbut you can't compare two maps with == or !=
the key of map must be any comparable type so it can't be slice or a map
Reading and Writing to a map
to read a value of map we use key as an index
func main() {
stars := map[string]string{
"lakers": "Luka Dončić",
"GSW": "steph the carry",
}
fmt.Println(stars["lakers"]) // Luka Dončić
}
and if we need to change a value of specific key stars["lakers"]= "Lebron James" this will change the value of lakers to be Lebron
in GO, map is a hash map so there is no order for keys, for example at printing it will loop over the map in a pseudo-random order
if we need to create a new pair stars["non_exisiting_key"]= "value" trying to read a value of non-existing key returns the type's zero value
stars := map[string]int{
"lakers": 2,
"gsw": 1,
"san_antonio": 5,
}
stars["gsw"]++ // 2
fmt.Println(stars) // map[gsw:2 lakers:2 san_antonio:5]
fmt.Println(stars["lakers"]) // 2
stars["non_existing_key"]++ // creates a new key with the zero value 0 then increments it
fmt.Println(stars["non_existing_key"]) // 1
Comma ok Idiom
used when you need to know if a key exists or not cause if you check by doing stars["lakers"]==0 as if you check if it doesn't exist it will return the zero value but it isn't optimal cause you don't know if it doesn't actually exist or it exists with value 0
so the comma ok idiom helps to tell the difference between non-existing keys, and existing zero values keys
m := map[string]int{
"Hello": 5,
"world": 0,
}
v, ok = m["world"]
fmt.Println(v, ok) // 0 true
first variable gets the value and second gets true or false
Deleting
using delete() function that doesn't return a value
- it deletes pairs by key
- if key doesn't exist or the map is
nilnothing happens
Emptying map
clear(x) to empty the map x unlike slices → clear with maps sets the length to zero
Comparing maps
just like slices where we used slices.Equal and slices.EqualFunc there is map.Equal and map.EqualFunc
but the difference with map.Equal is that maps aren't ordered data structure so those maps are equal
m := map[string]int{
"hello": 5,
"world": 10,
}
n := map[string]int{
"world": 10,
"hello": 5,
}
Using Maps as sets
what are the properties of sets ?
- no duplicates
- Fast membership check (if value exists or not)
- often unordered
Go doesn't have the built-in datatype sets so why exactly we use maps to stimulate not any other datatype
- maps have keys with fast lookup (time complexity O(1) on avg)
- and they are unordered
Maps' Keys are Unique values so we are gonna use them as our set base
intSet := map[int]bool{}
vals := []int{4, 10, 12, 42, 8, 4, 12, 199, 29, 42}
for _, v := range vals {
intSet[v] = true
}
fmt.Println(len(vals), len(intSet)) // 10 7
btw we don't care what is stored in the value of each key so it doesn't have to be true it can be intSet[v] = "exists" but it is best to be true so if we wanna check if a key exists later we will just do if intSet[242] (242 doesn't exist so it will return the zero value of type bool which is false) instead of if intSet[242]=="exists"
Takes
Map Declaration: Maps can be declared as
var m map[keyType]valueType(nil map) or using a literalm := map[keyType]valueType{}- nil maps cannot be written to, but literals can
Reading & Writing: Access map values with
m[key]- Reading a non-existent key returns the zero value of the type and writing to a non-existent key creates it
Comma-ok Idiom: Use
v, ok := m[key]to safely check if a key exists differentiating zero values from missing keysDeleting & Clearing: Use
delete(m, key)to remove a key;clear(m)empties the map completelyMaps as Sets: Maps can simulate sets by storing keys with dummy values (bool) leveraging uniqueness and O(1) lookup
Coming Next
the next break will be about Structs in GO so stick around for next break where we will break more stuff
feel free to reach out to me
