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
11: Arrays and Slices
If you're coming from Python or JavaScript, the first thing that's going to trip you up in Go is that we have two different things that look almost identical: arrays and slices. Let's clear that up and get into how you'll actually use them in a real project.
Wait, why are there both arrays and slices? Can't I just use one?
In most languages, you have one "list" type that grows as you add things to it. In Go, that's a slice. An array, on the other hand, has a fixed size that is part of its type. Once you define an array of 5 integers, it can never be 6. Ever.
I'll be honest: you will rarely use arrays in your day-to-day Go code. They're useful for very specific things, like representing a cryptographic hash or a fixed set of RGB values. For everything else—user lists, database results, file lines—you want a slice.
// This is an array. Its size is 3. Fixed.
var coordinates [3]int = [3]int{10, 20, 30}
// This is a slice. It looks similar, but the brackets are empty.
// It can grow and shrink.
var tags []string = []string{"golang", "tutorial"}
How do I add elements to a slice if there's no .push() method?
Go doesn't use methods on slices for adding elements. Instead, we use the built-in append function. One thing that confuses beginners is that append doesn't modify the slice in place; it returns a new slice header that points to the updated data.
This is why you'll always see the pattern s = append(s, value). If you forget to assign the result back to your variable, your slice won't actually grow.
func main() {
inventory := []string{"laptop", "mouse"}
// Adding one item
inventory = append(inventory, "keyboard")
// You can even append one slice to another using the "..." spread operator
extras := []string{"monitor", "webcam"}
inventory = append(inventory, extras...)
fmt.Println(inventory) // [laptop mouse keyboard monitor webcam]
}
What is the actual difference between "length" and "capacity"?
This is where the "under the hood" part of Go becomes important. A slice is actually just a small header that points to a real array sitting somewhere in memory. The length is how many elements are currently in the slice. The capacity is how many elements the underlying array can hold before Go has to allocate a brand new, larger array and copy everything over.
If you know you're going to store 1,000 items, don't start with an empty slice and append 1,000 times. That forces Go to resize the array multiple times, which is slow. Use make to pre-allocate the capacity.
// Create a slice with length 0, but capacity for 100 elements.
// It's empty, but it won't need to re-allocate until the 101st item.
users := make([]string, 0, 100)
How does the slicing syntax [low:high] actually work?
You can create a new slice from an existing one using the [start:end] syntax. It's important to remember that the start is inclusive and the end is exclusive. Also, because slices point to the same underlying array, changing an element in the sub-slice changes it in the original too.
func main() {
numbers := []int{0, 1, 2, 3, 4, 5}
// Grab elements from index 1 up to (but not including) 4
subset := numbers[1:4]
fmt.Println(subset) // [1 2 3]
// Warning: this modifies the original 'numbers' slice!
subset[0] = 99
fmt.Println(numbers) // [0 99 2 3 4 5]
}📋 Practical Task
Build a Guest List Manager
You need to write a small program that manages a guest list for an event. Follow these requirements:
- Start by creating a slice of strings called
guestListwith an initial capacity of 10, but a length of 0. - Use
appendto add three names to the list: "Alice", "Bob", and "Charlie". - The event has a "VIP section" which consists of the first two people who signed up. Create a new slice called
vipsby slicing theguestList. - Change the first VIP's name to "Alice (VIP)".
- Print both the
vipsslice and the originalguestListslice to verify that the change reflected in both.
There are no comments for now.