Avoid These Hidden Go Pitfalls: Octal Literals, Integer Overflow, Float Comparison, Slices & Maps
This article reveals thirteen subtle Go programming mistakes—from octal literals and integer overflow to floating‑point comparison, slice length vs. capacity, map initialization, and value copying—providing clear explanations, real‑world analogies, and concrete best‑practice code fixes to prevent bugs and performance issues.
Go developers often encounter hard‑to‑spot bugs that can cause logical errors or performance bottlenecks. This guide enumerates thirteen common mistakes (errors 17‑29), explains why they occur, and offers best‑practice solutions with runnable code examples.
Error 17: Octal Literal Confusion
Numeric literals starting with 0 are interpreted as octal, which can lead to unexpected values.
package main
import "fmt"
func main() {
number := 0755 // octal literal
fmt.Printf("FunTester: permission number is %d
", number)
}Use the 0o prefix to make octal literals explicit.
package main
import "fmt"
func main() {
number := 0o755 // explicit octal
fmt.Printf("FunTester: permission number is %d
", number)
}Error 18: Ignoring Integer Overflow
Adding two large int values can overflow, producing incorrect results.
package main
import "fmt"
func calculateFunTester(a, b int) int { return a + b }
func main() {
a := 2147483647 // max int32
b := 1
result := calculateFunTester(a, b)
fmt.Printf("FunTester: result is %d
", result) // overflow
}Detect overflow by checking sign changes before returning.
package main
import (
"errors"
"fmt"
)
func calculateFunTester(a, b int) (int, error) {
result := a + b
if (a > 0 && b > 0 && result < 0) || (a < 0 && b < 0 && result > 0) {
return 0, errors.New("FunTester: integer overflow")
}
return result, nil
}
func main() {
a := 2147483647
b := 1
result, err := calculateFunTester(a, b)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("FunTester: result is %d
", result)
}Error 19: Floating‑Point Comparison Pitfalls
Direct equality checks on floating‑point numbers are unreliable due to representation errors.
package main
import "fmt"
func main() {
a := 0.1
b := 0.2
sum := a + b
if sum == 0.3 {
fmt.Println("FunTester: equal")
} else {
fmt.Println("FunTester: not equal") // actually prints this
}
}Compare using a tolerance (delta) instead of direct equality.
package main
import (
"fmt"
"math"
)
func main() {
a := 0.1
b := 0.2
sum := a + b
delta := math.Abs(sum - 0.3)
if delta < 1e-9 {
fmt.Println("FunTester: equal via delta")
}
}Error 20: Misunderstanding Slice Length and Capacity
lenreturns the number of elements, while cap returns the underlying array capacity; ignoring capacity can hurt performance.
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
fmt.Printf("FunTester: len=%d, cap=%d
", len(s), cap(s))
}Initialize slices with explicit length and capacity using make.
package main
import "fmt"
func main() {
s := make([]int, 3, 5) // len=3, cap=5
fmt.Printf("FunTester: len=%d, cap=%d
", len(s), cap(s))
}Error 21: Inefficient Slice Initialization
Repeated append without pre‑allocating capacity triggers many allocations.
package main
import "fmt"
func main() {
var s []int
for i := 0; i < 1000; i++ {
s = append(s, i)
}
fmt.Printf("FunTester: len=%d, cap=%d
", len(s), cap(s))
}Pre‑set capacity to avoid re‑allocations.
package main
import "fmt"
func main() {
s := make([]int, 0, 1000) // capacity 1000
for i := 0; i < 1000; i++ {
s = append(s, i)
}
fmt.Printf("FunTester: len=%d, cap=%d
", len(s), cap(s))
}Error 22: Nil vs. Empty Slice Confusion
A nil slice and an empty slice behave differently; treating them uniformly prevents bugs.
package main
import "fmt"
func main() {
var nilSlice []int
emptySlice := []int{}
fmt.Println("nilSlice == nil?", nilSlice == nil)
fmt.Println("emptySlice == nil?", emptySlice == nil)
}Return an empty slice instead of nil when a slice is expected.
package main
import "fmt"
func getFunTesterSlice() []int { return []int{} }
func main() {
slice := getFunTesterSlice()
fmt.Println("FunTester: slice empty?", len(slice) == 0)
}Error 23: Accessing Slice Without Empty Check
Indexing a nil or empty slice causes a runtime panic.
package main
import "fmt"
func main() {
var s []int
if len(s) > 0 && s[0] == 10 {
fmt.Println("FunTester: first element is 10")
} else {
fmt.Println("FunTester: slice is empty")
}
}Error 24: Incomplete Slice Copy
Copying to a destination slice that is too short truncates data.
package main
import "fmt"
func main() {
original := []int{1, 2, 3}
copySlice := make([]int, 2)
copy(copySlice, original) // copies only first two elements
fmt.Printf("FunTester: copySlice = %v
", copySlice)
}Allocate the destination with the same length as the source.
package main
import "fmt"
func main() {
original := []int{1, 2, 3}
copySlice := make([]int, len(original))
copy(copySlice, original)
fmt.Printf("FunTester: copySlice = %v
", copySlice)
}Error 25: Slice Append Side‑Effects
Appending to a slice inside a function may modify a shared underlying array, leaving the caller unchanged.
package main
import "fmt"
func modifySlice(s []int) {
s = append(s, 4)
fmt.Println("FunTester: modifySlice internal s =", s)
}
func main() {
s := []int{1, 2, 3}
modifySlice(s)
fmt.Println("FunTester: main s =", s) // unchanged
}Create an explicit copy before modifying.
package main
import "fmt"
func modifySlice(s []int) {
copied := make([]int, len(s))
copy(copied, s)
copied = append(copied, 4)
fmt.Println("FunTester: modifySlice internal copied =", copied)
}
func main() {
s := []int{1, 2, 3}
modifySlice(s)
fmt.Println("FunTester: main s =", s)
}Error 26: Slice‑Related Memory Leak
Keeping references to a larger underlying array via a subslice prevents the garbage collector from freeing memory.
package main
import "fmt"
func main() {
nodes := []*int{new(int), new(int), new(int)}
subslice := nodes[:2]
fmt.Printf("FunTester: subslice = %v
", subslice)
}Explicitly nil out elements that are no longer needed.
package main
import "fmt"
func main() {
nodes := []*int{new(int), new(int), new(int)}
for i := 2; i < len(nodes); i++ {
nodes[i] = nil // release
}
subslice := nodes[:2]
fmt.Printf("FunTester: subslice = %v
", subslice)
}Error 27: Inefficient Map Initialization
Creating a map without an initial capacity causes repeated rehashing.
package main
import (
"fmt"
)
func main() {
m := make(map[string]int)
for i := 0; i < 1000; i++ {
key := fmt.Sprintf("key%d", i)
m[key] = i
}
fmt.Printf("FunTester: map size = %d
", len(m))
}Specify the expected size when calling make.
package main
import (
"fmt"
)
func main() {
m := make(map[string]int, 1000) // pre‑allocate capacity
for i := 0; i < 1000; i++ {
key := fmt.Sprintf("key%d", i)
m[key] = i
}
fmt.Printf("FunTester: map size = %d
", len(m))
}Error 28: Map Memory Leak
Even after clearing entries, the underlying bucket memory remains allocated.
package main
import "fmt"
func main() {
m := make(map[int][]int, 10)
for i := 0; i < 100; i++ {
m[i] = make([]int, 1000)
}
for k := range m {
m[k] = nil // clear values
}
fmt.Println("FunTester: map cleared")
}Re‑create the map to release the old memory.
package main
import "fmt"
func main() {
m := make(map[int][]int, 10)
// ... populate ...
m = make(map[int][]int, 10) // new map, old memory freed
fmt.Println("FunTester: map re‑created, old memory released")
}Error 29: Incorrect Value Comparison
Using == on structs containing uncomparable fields is illegal; reflect.DeepEqual or custom comparators should be used.
package main
import (
"fmt"
"reflect"
)
type FunTester struct {
Name string
Age int
}
func main() {
a := FunTester{Name: "FunTester", Age: 30}
b := FunTester{Name: "FunTester", Age: 30}
if reflect.DeepEqual(a, b) {
fmt.Println("FunTester: equal via DeepEqual")
}
}Prefer reflect.DeepEqual for deep struct comparison or implement a dedicated equality function.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
