Values, Constants & Numbers
Integer types and overflow, signed vs unsigned, strings, runes and bytes, iota constants, and control flow.
7 questions
JuniorTheoryCommonWhat integer sizes does Go provide, and what determines the width of int?
What integer sizes does Go provide, and what determines the width of int?
Go has fixed-width integers of 8, 16, 32, and 64 bits, signed (int8…int64) and unsigned (uint8…uint64). The plain int and uint are platform-dependent — 64-bit on virtually all modern targets, 32-bit on 32-bit GOARCH builds — with the width fixed by the implementation.
Common mistakes
- ✗Assuming
intis always 32 bits, or always 64 bits, regardless of the target platform - ✗Believing
intwidth is chosen dynamically based on the stored value rather than fixed at compile time - ✗Confusing
intwithint32and relying on a guaranteed 32-bit width in serialized data
Follow-up questions
- →What is
uintptrand how does its width relate toint? - →Why should serialized formats use
int64instead ofint?
JuniorTheoryCommonWhat scopes does Go have, and how is cross-package visibility decided?
What scopes does Go have, and how is cross-package visibility decided?
Go resolves identifiers through nested scopes: block scope (the innermost {}, which allows shadowing), function scope, file scope (imports), package scope (top-level declarations visible to every file in the package), and the universe scope (builtins). Cross-package visibility is separate and decided by case: a Capitalized identifier is exported (public), a lowercase one is unexported.
Common mistakes
- ✗Looking for
public/privatekeywords — Go decides export by letter case - ✗Forgetting block scope exists and that inner blocks can shadow outer names
- ✗Thinking package-scope declarations are visible only within their own file
Follow-up questions
- →How does shadowing in an inner block affect an outer variable?
- →Is an unexported field reachable via an exported embedded struct?
JuniorTheoryCommonWhat is the difference between signed and unsigned integer types in Go?
What is the difference between signed and unsigned integer types in Go?
Signed types (int8…int64, int) use two's complement and hold negative and positive values. Unsigned types (uint8…uint64, uint, uintptr) hold only non-negative values; on overflow they wrap modulo 2^n rather than trapping.
Common mistakes
- ✗Thinking unsigned arithmetic traps or saturates on overflow — Go wraps modulo 2^n with no error
- ✗Believing a signed type devotes one whole magnitude bit to a sign flag rather than using two's complement
- ✗Assuming
uintcan briefly hold a negative intermediate value before being clamped
Follow-up questions
- →What happens when you subtract a larger
uintfrom a smaller one? - →Why does Go forbid implicit conversion between
intanduint?
JuniorTheoryCommonHow does switch-case work in Go, and what does break do?
How does switch-case work in Go, and what does break do?
A Go switch runs only the first matching case and then stops: there is no implicit fall-through, so an explicit break is rarely needed. Inside a switch nested in a loop, break exits only the switch (use a label for the loop). fallthrough forces the next case, a case can list comma-separated values, and an expression-less switch {} acts like an if/else chain.
Common mistakes
- ✗Expecting C-style fall-through and adding a
breakafter every case - ✗Thinking
breakin a switch inside a loop exits the loop, not the switch - ✗Forgetting
fallthroughexists to deliberately run the next case
Follow-up questions
- →How do you break out of a loop from inside a switch in its body?
- →What is the difference between a type switch and a value switch?
JuniorTheoryOccasionalHow do you compute the range of int64 for positive numbers in Go?
How do you compute the range of int64 for positive numbers in Go?
int64 is a signed two's-complement type, so it splits its 64 bits between negatives and non-negatives: it spans −2^63 … 2^63−1. The positive range is therefore 0 … 2^63−1, which equals 9223372036854775807 — the value of math.MaxInt64.
Common mistakes
- ✗Computing the positive ceiling as 2^64−1 — that is the unsigned
uint64maximum, notint64's - ✗Including 2^63 itself as the maximum instead of 2^63−1 (off-by-one from forgetting zero)
- ✗Thinking a sign bit is held separately from the value rather than being part of two's complement
Follow-up questions
- →What is the most negative
int64value, and why is it not the mirror of the maximum? - →What does negating
math.MinInt64evaluate to, and why does it overflow?
JuniorDebuggingOccasionalWhy does this average return 1.0 for []int{1, 2} instead of 1.5?
Why does this average return 1.0 for []int{1, 2} instead of 1.5?
sum / len(nums) is integer division, which truncates toward zero before the float64(...) conversion — 3 / 2 is 1, then cast to 1.0. An empty slice also panics on divide-by-zero. Fix: convert first, float64(sum) / float64(len(nums)), and guard len(nums) == 0.
Common mistakes
- ✗Converting to
float64after the division instead of before - ✗Forgetting integer division truncates toward zero rather than rounding
- ✗Not guarding
len(nums) == 0, which panics on divide-by-zero
Follow-up questions
- →Why does
float64(sum / len(nums))still truncate even though the result is a float? - →What value does
5 / 2produce in Go, and how does it differ from5.0 / 2?
JuniorCodeOccasionalWhat does len(s) versus utf8.RuneCountInString(s) print for s := "héllo"?
What does len(s) versus utf8.RuneCountInString(s) print for s := "héllo"?
It prints 6 5. len(s) counts bytes, and é is two bytes in UTF-8, so the byte length is 6 while the rune (character) count is 5. Ranging with for i, r := range s iterates runes, while indexing s[i] yields a single byte, not a character.
Common mistakes
- ✗Assuming
len(s)returns the character count — it returns the byte count - ✗Thinking
s[i]indexes runes; it indexes bytes - ✗Forgetting multi-byte UTF-8 characters like
éoccupy more than one byte
Follow-up questions
- →How many iterations does
for i, r := range sperform, and what isiafter theé? - →Why does
[]rune(s)allocate whilerangeover the string does not?