Data Types & Constants (iota)
You know the four headline types already. Now you'll meet Go's full numeric family (sized ints, unsigned ints, floats), understand the real difference between byte , rune and string , and master iota — Go's elegant way to build enums and bit flags without typing a single number by hand.
Learn Data Types & Constants (iota) in our free Go course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.
Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ The Numeric Family
Plain int is 64 bits on modern machines and is what you'll use 95% of the time. But Go gives you precise control when you need it: int8/16/32/64 for signed whole numbers of a specific size, uint variants for unsigned (zero-and-up) values, and float32/float64 for decimals. Reach for the sized types when memory matters (huge slices) or when an external format demands an exact width.
Your turn — fill in the three blanks. Remember a colour channel is 0–255 (perfect for an unsigned 8-bit type), and you must convert before mixing sizes.
2️⃣ Bytes, Runes & Strings
This trips up almost everyone coming from other languages. A Go string is a sequence of bytes , and len(s) counts those bytes — not characters. Because Go uses UTF-8, an accented or non-Latin character can take 2–4 bytes. A rune (an alias for int32 ) represents one real Unicode character, and ranging over a string decodes runes for you. A byte is an alias for uint8 .
3️⃣ Constants & iota
Go has no enum keyword. Instead it gives you iota — a counter that resets to 0 at the start of each const (...) block and increments by one on every line. Write the expression once and Go repeats it down the list. Pair it with a named type (like type Weekday int ) and you get type-safe enums. With 1 << iota you get powers of two — perfect for bit flags you can combine with | .
Your turn — complete this log-level enum. The first line starts the counter; the rest follow automatically.
🧩 Reorder Challenge
These lines define a bit-flag constant block, but they're scrambled. Put them in the correct order so the program compiles and prints Write = 2 (assume a func main wraps the print).
- package main; import "fmt"
- Read = 1 << iota
- fmt.Println("Write =", Write)
Why: the package and import come first. The const ( block must open before its members. Read = 1 << iota sets the pattern on line 0 (value 1), and Write on the next line repeats it at iota=1, giving 1 << 1 = 2 . The block must be closed with ) before any code references Write .
Pro Tips
- 💡 Default to plain int and float64 . Only reach for sized types when an API, file format, or memory budget forces it.
- 💡 Use _ = iota to skip 0 if you want your enum to start at 1 — the first line is discarded.
- 💡 To iterate characters safely, range over the string (runes), not over s[i] (bytes), or non-ASCII text will break.
- 💡 Bit flags read cleanly : store combined permissions in one int and test with flags&Write != 0 .
Common Errors (and the fix)
- "constant 300 overflows int8" — you tried to store a value larger than the type allows. An int8 maxes out at 127; use a bigger type or a different value.
- Counting characters with len(s) gives a wrong number — len returns bytes. Use utf8.RuneCountInString(s) or range over the string to count real characters.
- "mismatched types int and int64" — even two integer types won't mix automatically. Convert: int64(x) + y .
- iota counts blank lines and comments? No — it counts ConstSpec lines . Every entry in the block (even _ ) advances iota by one.
📋 Quick Reference
Type
Meaning
Range / Note
int / int64
Signed whole number
±9.2 quintillion
int8
Tiny signed int
-128 .. 127
uint8 / byte
Unsigned 8-bit
0 .. 255
rune / int32
One Unicode char
'A' == 65
float64
Decimal (default)
~15 digits precision
iota
Const counter
0,1,2,… per block
🧠 Quick Recall
Predict the output before you reveal the answer.
5 — the é is two bytes in UTF-8, so the 4-character word is 5 bytes long. Count characters with utf8.RuneCountInString to get 4.
2 — iota is 0 for A, 1 for B, 2 for C. The = iota expression repeats implicitly on each line.
B — Unicode code point 66 is the capital letter B, and %c prints the character for that value.
Frequently Asked Questions
Rarely for everyday counters. Use a sized type when you're matching a binary file format, a network protocol, or trimming memory in a very large slice. Otherwise plain int is idiomatic and fast.
Q: Why does len on a string give a strange number?
len counts bytes, and UTF-8 uses multiple bytes for non-ASCII characters. To count characters, range over the string (which yields runes) or call utf8.RuneCountInString .
Yes — assign that line to the blank identifier _ . A common pattern is _ = iota on the first line so your real values start at 1.
Mini-Challenge: Planet Enum
Bring it together: an iota enum plus a float64 for mass. Write it yourself and match the example output in the comments.
🎉 Lesson Complete!
- ✅ Go's numeric family: sized int / uint types and float32 / float64
- ✅ string is bytes, len counts bytes, and a rune is one Unicode character
- ✅ byte = uint8 , rune = int32
- ✅ iota builds enums and (with 1 << iota ) bit flags automatically
- ✅ Sized types never mix implicitly — convert with int64(x) , int(x) , etc.
- ✅ Next lesson: Control Flow — make decisions with if and switch
Practice quiz
What is the range of an int8?
- 0 to 255
- 0 to 127
- -128 to 127
- -256 to 255
Answer: -128 to 127. A signed 8-bit integer (int8) holds values from -128 to 127.
What does len("café") return in Go?
- 5
- 4
- 3
- 8
Answer: 5. len counts bytes, and é is two bytes in UTF-8, so the 4-character word is 5 bytes long.
A rune in Go is an alias for which type?
- uint8
- int64
- byte
- int32
Answer: int32. A rune is an alias for int32 and represents a single Unicode code point.
A byte in Go is an alias for which type?
- int8
- uint8
- int32
- rune
Answer: uint8. byte is an alias for uint8 — one raw, unsigned 8-bit value.
What does fmt.Printf("%c", rune(66)) print?
- B
- 66
- A
- b
Answer: B. Unicode code point 66 is the capital letter B, and %c prints the character for that value.
Which floating-point type is Go's default and more precise?
- float32
- float16
- float64
- decimal
Answer: float64. float64 is the default float type in Go and offers roughly 15 digits of precision.
What is the value of letter in: var letter rune = 'A'; fmt.Println(letter)?
- A
- 65
- 0
- 'A'
Answer: 65. A rune is an integer type, and the Unicode value of 'A' is 65, which is what Println shows.
Given const ( A = iota; B; C ), what does C equal?
- 0
- 1
- 3
- 2
Answer: 2. iota is 0 for A, 1 for B, and 2 for C — the = iota expression repeats implicitly each line.
Will two different integer types like int and int64 mix automatically in an expression?
- Yes
- No — you must convert explicitly
- Only if same size
- Only with floats
Answer: No — you must convert explicitly. Go never mixes numeric types implicitly; you must convert, e.g. int64(x) + y.
How should you count the actual characters in a UTF-8 string?
- len(s)
- cap(s)
- range over the string or utf8.RuneCountInString(s)
- s.length
Answer: range over the string or utf8.RuneCountInString(s). len counts bytes; range over the string yields runes, or use utf8.RuneCountInString to count characters.
Continue this course
- Previous: Variables
- Next: Control Flow (if, switch)