Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
180: Common Go Interview Questions on Slices vs Arrays
Why would I ever use an array if slices are so much more flexible?
I get this question a lot. On the surface, arrays seem like a restricted version of slices. You're right that in 95% of your Go code, you'll use slices. But arrays have a specific property: their size is part of their type. An [3]int is a completely different type than a [4]int.
You use arrays when you have a fixed mathematical or structural constraint that should never change. Think of an RGB color value or a 3D coordinate. If you're representing a point in 3D space, you don't want a slice that could accidentally grow to 4 dimensions.
type Point3D [3]float64
func calculateDistance(p Point3D) float64 {
// The compiler guarantees p always has exactly 3 elements.
// No need to check len(p) before accessing p[2].
return p[0] * p[0] + p[1] * p[1] + p[2] * p[2]
}
Another huge difference is that arrays are value types. If you assign one array to another, Go copies the entire thing. Slices, however, are just headers pointing to an underlying array. Copying a slice header is cheap; copying a 10,000-element array is not.
If I pass a slice to a function and change an element, does the caller see it?
Yes, they do. And this is a classic interview "gotcha." To understand why, you have to stop thinking of a slice as "a list" and start thinking of it as a slice header. That header contains a pointer to the underlying array, a length, and a capacity.
When you pass a slice to a function, Go passes that header by value. You get a copy of the pointer, the length, and the capacity. Since the copy of the pointer still points to the same memory address as the original, modifying an element affects the same underlying data.
func updateFirstElement(data []int) {
if len(data) > 0 {
data[0] = 999 // This modifies the underlying array
}
}
func main() {
scores := []int{10, 20, 30}
updateFirstElement(scores)
fmt.Println(scores[0]) // Prints 999
}
What's actually happening during an append?
This is where things get tricky. append doesn't just "add an item." It checks if the underlying array has enough capacity to hold the new element. If it does, it just updates the element and returns a new header with an incremented length.
But if the capacity is full, Go does something expensive: it allocates a brand new, larger array, copies all the old elements over, adds the new one, and returns a header pointing to this new location. If you're passing a slice into a function and calling append inside that function, the caller might not see the new elements because the function's local slice header was updated to point to a new array, but the caller's header still points to the old one.
func tryToAdd(s []int) {
s = append(s, 4) // If this triggers a reallocation, the caller's slice is unchanged
}
func main() {
// Create a slice with length 3 and capacity 3
nums := make([]int, 3, 3)
tryToAdd(nums)
fmt.Println(len(nums)) // Still 3! The append happened on a copy of the header.
}
This is why you almost always see append used as s = append(s, val). You must capture the returned header to ensure you're tracking the correct underlying array.
📋 Practical Task
Fixing the Slice-Header Mutation Bug
You are reviewing a teammate's code for a system that processes a batch of sensor readings. The goal is to have a function called filterOutliers that removes any reading above 100. However, the teammate complained that the original slice in main isn't actually being updated when the function runs.
Your Task: Modify the filterOutliers function or the way it is called in main so that the original slice is correctly updated to reflect the filtered results. You can choose to return the new slice or use a pointer to the slice header.
package main
import "fmt"
func filterOutliers(readings []float64) {
var filtered []float64
for _, v := range readings {
if v <= 100.0 {
filtered = append(filtered, v)
}
}
// BUG: The local 'filtered' slice is updated,
// but the 'readings' slice in main remains unchanged.
readings = filtered
}
func main() {
data := []float64{23.5, 105.2, 44.1, 110.0, 12.2}
fmt.Printf("Before: %v\n", data)
filterOutliers(data)
fmt.Printf("After: %v\n", data) // Currently prints the original unfiltered list
}There are no comments for now.