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.
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?vardeclares 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
pricesnow looks like{2.99, 5.99, 5.99},empty_arrconsists of only zeroes and the non-initialized values ofhalf_empty_arrare 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?
A slice is a flexible, dynamic 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 = 3,cap = 3- Backed by a hidden array of 3 ints.
If empty:
myslice := []int{}
len = 0,cap = 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 = 5,cap = 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
| Method | Syntax Example | Length | Capacity | Notes |
|---|---|---|---|---|
| Literal | []int{1,2,3} | 3 | 3 | Short and clean |
| Empty literal | []int{} | 0 | 0 | Empty but valid |
| From array | arr[2:4] | 2 | arr.len-2 | Capacity depends on start index |
make() (full) | make([]int, 5, 10) | 5 | 10 | Ideal for performance setups |
make() (short) | make([]int, 5) | 5 | 5 | Cleaner, 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 indexa(inclusive) tob(exclusive) - soa's in butb'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]
slicepoints toarray[1]len(slice) = 3(b-a)cap(slice) = 4(fromato 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 elementscap = 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'llappend()later
Why use make() over literal?
This post is for subscribers only
Subscribe to continue reading