-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
13: Maps
Listen, I've seen this exact bug trip up dozens of junior devs: the assumption that if you get a value back from a map, that key actually existed in the map. In many languages, accessing a missing key throws an error or returns null. In Go, it doesn't. It returns the zero value for the map's value type.
The Zero Value Trap
Imagine you're building a simple game where you track player scores in a map. You might write something like this:
scores := map[string]int{"Alice": 10, "Bob": 0}
fmt.Println(scores["Charlie"]) // Output: 0
At first glance, you might look at that 0 and think, "Oh, Charlie is in the game and he hasn't scored any points yet." But Charlie isn't even in the map. Go just saw that you wanted an int and, since the key was missing, it gave you the default int value of 0. This is dangerous because you can't tell the difference between a player who is missing and a player who actually has a score of zero.
The "Comma Ok" Idiom
To fix this, you need to use what we call the "comma ok" idiom. When you access a map, Go can actually return two values: the value itself, and a boolean that tells you if the key was actually present.
scores := map[string]int{"Alice": 10, "Bob": 0}
if val, ok := scores["Charlie"]; ok {
fmt.Printf("Charlie's score is %d\n", val)
} else {
fmt.Println("Charlie isn't in the system!")
}
if val, ok := scores["Bob"]; ok {
fmt.Printf("Bob's score is %d\n", val) // This will actually print!
}
I always recommend using this pattern whenever a zero value is a legitimate piece of data in your domain. It's the only way to be certain about the state of your data.
Initializing and Managing Your Data
You have two main ways to get a map started. For small, known sets of data, use a map literal. For dynamic data—like things you're loading from a database—use make.
// Literal: Great for configuration or fixed lookups
routes := map[string]string{
"/": "Home Page",
"/about": "About Us",
}
// make: Essential for empty maps you intend to fill later
userCache := make(map[int]string)
userCache[101] = "Jane Doe"
One quick warning: never try to add an element to a nil map (a map declared without make or a literal). Your program will panic and crash instantly. Always initialize your maps.
When it comes to removing items, Go provides the built-in delete function. It's clean, and interestingly, it doesn't care if the key exists or not—if the key is already gone, delete just does nothing without complaining.
delete(routes, "/about")
Maps are Reference Types
Here is a nuance that often surprises people: maps are reference types. If you pass a map into a function and that function modifies the map, the original map is changed. You aren't passing a copy of the map; you're passing a pointer to the underlying data structure.
I've found this incredibly useful for sharing state across different parts of a program, but it can lead to "spooky action at a distance" if you aren't careful. If you need to protect a map from being changed, you'll either need to copy it manually into a new map or use a sync.Mutex if you're working with goroutines (which we'll tackle in a later lesson).
📋 Practical Task
Build a DNS Cache Simulator
Your task is to create a small program that simulates a DNS cache. You need to implement a system that stores domain names (keys) and their corresponding IP addresses (values).
Requirements:
- Create a map called
dnsCache. - Add three entries to the map:
"google.com","github.com", and"golang.org". - Write a function called
resolve(domain string)that:- Checks if the domain exists in the cache using the "comma ok" idiom.
- If it exists, prints:
"IP found: [IP address]". - If it doesn't exist, prints:
"Domain not found in cache".
- In your
mainfunction, callresolvefor a domain that exists and one that doesn't. - Use the
deletefunction to remove"github.com"from the cache, then callresolve("github.com")again to verify it's gone.
There are no comments for now.