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 Jump Into A Hole Stickers - Find & Share on GIPHY


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

go
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

go
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

go
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

go
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

go
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 len tells you how many pairs are in it
  • zero value for a map is nil
  • maps are only comparable with nil but 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

go
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

go
    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

go
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 nil nothing 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

go
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

go
    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 literal m := 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 keys

  • Deleting & Clearing: Use delete(m, key) to remove a key; clear(m) empties the map completely

  • Maps 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 Peace Out GIFs | Tenor