members-only post

More to Go: Clean Code & Core Concepts

A hands-on walkthrough of Go’s core building blocks. Arrays, slices, loops, functions, structs, and maps - explained with performance in mind. No fluff, just clarity.
More to Go: Clean Code & Core Concepts

We're baack

Let's get into the real Go deal with this one shall we hehe.

Go Arrays

Arrays in Go can either be declared via the var keyword or our beloved walrus operator :=:

var <ARRAY_NAME> = [length]datatype{values}

# with inferred length:
var <ARRAY_NAME> = [...]datatypes{values}

does the same as

<ARRAY_NAME> := [length]datatype{values}

# with inferred length:
<ARRAY_NAME> := [...]datatypes{values}
Remember the difference? var declares the variables with explicit type or zero-value and is (thereby) usable outside functions, directly on package level. The walrus operator := can only be used inside functions and the type is compiler-inferred.

Arrays: Examples & Operations

package main

import f "fmt"

func main() {
    prices := [3]float32{2.99, 5.99, 8.99}
    empty_arr := [5]int{}          // seems not initialized?
    half_empty_arr := [5]int{1, 2} // seems partially initialized
    prices[2] = prices[1]

    f.Println(prices[2])
    f.Println(empty_arr)
    f.Println(half_empty_arr[3])
}

What do you think is printed?

5.99
[0 0 0 0 0]
0
prices now looks like {2.99, 5.99, 5.99}empty_arr consists of only zeroes and the non-initialized values of half_empty_arr are also filled with zeroes.

Specific Partial Array Initializations

Interestingly, you can also do:

weird_array := [5]int{1:10,2:40}
f.Println(weird_array)

[0 10 40 0 0]

works with a nice concept of <ARR_POSITION>:<VALUE>.

len() works just as in Python, len(weird_array) = 5.


Go Slices - ArrayList goes brr

Java connoisseurs will love this one.

What is a Slice in Go?

slice is a flexibledynamic view into an array. Think of it like a window into an underlying array.

It has:

  • len() → How many elements are in the window.
  • cap() → How many elements the window could stretch to, without reallocating.

Slice Creation: 3 Main Ways

1. Literal Declaration

myslice := []int{1, 2, 3}
  • len = 3cap = 3
  • Backed by a hidden array of 3 ints.

If empty:

myslice := []int{}
  • len = 0cap = 0
Great for: small static lists, or passing data inline.

2. Slice from an Array

arr := [6]int{10, 11, 12, 13, 14, 15}
myslice := arr[2:4]
  • myslice = [12, 13]
  • len = 2 (elements 2 and 3)
  • cap = 4 (from index 2 → end of array)

Key concept: Capacity = distance from start index to end of backing array.

If we sliced from arr[0:4] → cap = 6

Great for: controlled slicing, memory views, performance work.

3. Using make()

myslice := make([]int, 5, 10)
  • len = 5cap = 10
  • Backed by array of 10 ints, but only first 5 "active".
myslice := make([]int, 5) // capacity = length = 5
Great for: preallocating memory, better performance in loops/appends.

To summarize

MethodSyntax ExampleLengthCapacityNotes
Literal[]int{1,2,3}33Short and clean
Empty literal[]int{}00Empty but valid
From arrayarr[2:4]2arr.len-2Capacity depends on start index
make() (full)make([]int, 5, 10)510Ideal for performance setups
make() (short)make([]int, 5)55Cleaner, less config

Remember:

  • You can grow a slice with append() up to its capacity without reallocating.
  • Slices are references: modifying a slice affects the underlying array.
  • Use make() when performance or growth matters.
  • Use slicing when working with large arrays efficiently.
Slices are just views into arrays; cheap and powerful, but watch out for hidden memory costs!

Slice elements...

... Accessing and modifying

slice := []int{10, 20, 30}
fmt.Println(slice[0]) // access
slice[2] = 50          // modify

... Appending Elements

slice = append(slice, 40, 50)
If capacity is exceeded, Go allocates a new underlying array.

... Append One Slice to Another

combined := append(slice1, slice2...)

... Change Slice Length via Reslicing

slice := []int{10, 20, 30, 40, 50}
newSlice := slice[1:4] // picks index 1 to 3 → [20, 30, 40]
slice[a:b] gives a view from index a (inclusive) to b (exclusive) - so a's in but b's not. Underlying array remains the same! No new memory yet.

Behind the scenes of slice[a:b]

array := [5]int{10, 20, 30, 40, 50}
slice := array[1:4]
  • slice points to array[1]
  • len(slice) = 3 (b - a)
  • cap(slice) = 4 (from a to end of array)
You don’t get a new array, just a pointer to part of it.

Slices with make()

s := make([]int, 5, 10)
  • len = 5 → number of usable elements
  • cap = 10 → total allocated backing array size
  • All elements default to zero values
s[0] = 99 // works, since len = 5
s[5] = 100 // panic: index out of range (len is still 5)
make() allocates a real backing array and gives you a slice pointing to it. Efficient for preallocation, useful when you'll append() later

Why use make() over literal?

This post is for subscribers only

Subscribe to continue reading