Go
Completed
-
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
7: Constants and iota
I'm building a small background job processor, and I've realized I need a way to categorize the priority of tasks. Some are "low" (like sending a weekly newsletter), and some are "critical" (like processing a payment). In my head, these are just numbers—0, 1, 2—but using raw numbers in my code is a recipe for a midnight bug hunt when I can't remember if 0 was "low" or "critical".
Hard-coding the basics
My first instinct is to just use variables, but that's dangerous. I don't want some rogue function accidentally changing the value of CriticalPriority to 42 halfway through the program's execution. That's where const comes in. Let's try the manual approach first:
const LowPriority = 0
const MediumPriority = 1
const HighPriority = 2
const CriticalPriority = 3
This works. It's safe, and it's clear. But it's also boring and repetitive. If I decide later that I need a "VeryLow" priority at the start, I have to manually re-number every single line below it. I've done this in a few languages, and it's a tedious slog. There has to be a cleaner way to handle "sequences" of constants in Go.
Letting Go do the counting
I remember hearing about iota. It's a weird little keyword that doesn't behave like a variable or a function—it's more of a pre-processor instruction. Let's see if I can replace those manual numbers with it. First, I'll group my constants into a block, which is common practice in Go for related values:
const (
LowPriority = iota
MediumPriority
HighPriority
CriticalPriority
)
Wait, I didn't even assign iota to the other three. Why does that work? I'll run a quick fmt.Println on them, and sure enough, they are 0, 1, 2, and 3. In Go, if you omit the expression on a line in a const block, it repeats the previous expression. So, Go is essentially seeing MediumPriority = iota, but iota increments every time it's encountered in the block.
It's a clever shorthand. Now, if I want to add a new level, I just slide it into the list, and the rest update themselves automatically. It removes the manual bookkeeping.
Shifting the starting line
Here is where I hit a snag. For this specific API I'm integrating with, "0" is actually reserved for "Unknown" or "Unset". If I let LowPriority be 0, my API calls are going to be misinterpreted. I want my priority scale to start at 1.
I tried just putting LowPriority = 1 at the top, but that broke the iota chain because I replaced the iota expression with a literal number. So, I'll try some basic math. Since iota starts at 0, I can just add 1 to it:
const (
LowPriority = iota + 1 // 0 + 1 = 1
MediumPriority // 1 + 1 = 2
HighPriority // 2 + 1 = 3
CriticalPriority // 3 + 1 = 4
)
That's exactly what I needed. The + 1 is applied to every line in the block because of that repetition rule I mentioned earlier. It's a simple pattern, but it saves me from having to manually offset every value.
Skipping a beat
One last thing. Let's say for some weird legacy reason, I need a gap in my numbers. Maybe MediumPriority is 2, but HighPriority needs to jump straight to 5. I can use the blank identifier (the underscore) to tell Go, "I know iota is incrementing here, but I don't want to assign this specific value to anything."
const (
LowPriority = iota // 0
MediumPriority // 1
_ // 2 (skipped!)
_ // 3 (skipped!)
HighPriority // 4
)
By using _, I've effectively burned those indices. It's not something you'll do every day, but when you're matching a pre-existing specification or a database schema, it's a lifesaver.
📋 Practical Task
Build a Network Connection State Machine
You are building a network monitoring tool. You need to define a set of constants to represent the state of a connection. Using a const block and iota, implement the following requirements:
- The states should be:
Disconnected,Connecting,Connected, andRetrying. - The
Disconnectedstate must have a value of 1 (not 0). - There should be a gap between
ConnectingandConnected(skip one value using the blank identifier).
Write a small main function that prints all four constants to the console to verify that the values are exactly what you expect.
There are no comments for now.