The Problem: Unexpected Behaviour with Leading Zeros
Recently, while working on a Go program that reverses an integer input, I encountered an unexpected issue: input values with leading zeros produced incorrect results. For example, entering 0123
returned 83
instead of 321
. After some debugging, I realised the cause was rooted in Go's interpretation of numeric literals.
Here’s a simplified version of the code:
package main
import "fmt"
func main() {
var inp int
fmt.Scan(&inp)
fmt.Println(inp) // Outputs unexpected values for leading-zero inputs
}
Entering 0123
resulted in 83
, a behaviour that puzzled me at first. Why would Go interpret 0123
as 83
? Let’s dive into the mechanics behind Go’s input handling to understand this better.
Insights into Numeric Literals in Go
In Go, numeric literals are interpreted based on their prefixes:
Decimal: Numbers without any prefix (e.g.,
123
) are treated as decimal.Octal: Numbers starting with
0
(like0123
) are interpreted as octal (base 8).Hexadecimal: Numbers prefixed with
0x
or0X
(like0x1F
) are hexadecimal (base 16).Binary: Numbers prefixed with
0b
or0B
(like0b1010
) are binary (base 2). This was introduced in Go 1.13.
Because 0123
has a 0
prefix, Go treats it as an octal number, converting it to 83
in decimal, which explains the unexpected output.
Avoiding the Trap: Solutions for Consistent Input Interpretation
If you’re dealing with user input that might include leading zeros and you want decimal interpretation, consider reading the input as a string and then converting it explicitly to an integer. Here’s an improved version of the original code:
package main
import (
"fmt"
"strconv"
)
func main() {
var inp string
fmt.Scan(&inp)
num, err := strconv.Atoi(inp)
if err != nil {
fmt.Println("Invalid input")
return
}
fmt.Println(num) // Now it will interpret as decimal regardless of leading zeros
}
Other Situations to Watch For in Go
This behaviour isn't limited to fmt.Scan
:
String parsing with
strconv.ParseInt
: Setting the base to0
in functions likestrconv.ParseInt("0123", 0, 64)
will detect the base from prefixes. If consistent decimal interpretation is needed, specify10
as the base instead.Hexadecimal and binary literals in code: These are helpful, but make sure they’re not used inadvertently, as
0x
and0b
prefixes will trigger hexadecimal and binary parsing.
Key Takeaways
This experience taught me the importance of understanding how Go interprets numeric literals. Here’s a summary of best practices when handling numeric input in Go:
Read input as strings when dealing with user data that could have ambiguous prefixes, and specify the desired base during conversion.
Explicitly specify the base when parsing numeric strings with
strconv
functions to avoid automatic base detection.Watch out for leading zeros in integer input, especially in cases where the base might unintentionally switch to octal.
Understanding these nuances can prevent bugs and ensure that your Go programs handle numeric inputs predictably.