David in Canada

 

Tech, life, and everything in between.

Day 5 of Learning Go: Understanding Slices and a Tricky Bug

Updated at # Tech # Go

Overview

Today I focused on Go’s core collection type: slices. Instead of treating this as a syntax exercise, I built a small CLI tool to process a list of integers and used it to explore common patterns and pitfalls.

The goal was to move from “knowing slices” to using them correctly under real conditions.


What I Built

A simple Number List Analyzer that:

This forced me to work with:


Key Implementation Patterns

Slice initialization

nums := make([]int, n)

Using make ensures the slice has the correct length for indexed assignment during input.


Iteration (idiomatic Go)

for _, num := range nums {
    total += num
}

Using range improves readability and avoids unnecessary indexing when the index is not needed.


Building derived slices

result := []int{}
for _, num := range nums {
    if num > 10 {
        result = append(result, num)
    }
}

This pattern is fundamental for filtering and transformation.


Subtle Bug: Slice Aliasing

Initial implementation

newArray := nums[0:0]

At first glance, this looks like an efficient way to reuse memory. However, this introduces aliasing: both slices share the same underlying array.

Consequence

Appending to newArray modified the original nums, leading to incorrect downstream results (e.g., reverse output).

This is a classic example of Go’s slice semantics causing unexpected side effects.


Fix

newArray := []int{}

By allocating a new slice, I ensured isolation between data structures.


Key Takeaways

This is a good reminder that Go trades abstraction for performance transparency. You get control, but you are also responsible for understanding the memory model.


Reflection

This was the first time I ran into a bug that wasn’t about syntax or logic, but about data structure behavior.

Understanding why the bug happened—not just fixing it—was the most valuable part of today’s work.


Next Steps