Arrays in Go
An array in Go is a fixed-size collection of elements of the same type. Unlike other programming languages, Go arrays have a fixed length that cannot be modified after declaration.
Array Declaration and Basic Operations
Arrays are declared using the following syntax:
var variable_name [size]data_type
var numbers [5]int
numbers[0] = 10
numbers[1] = 20
numbers[2] = 30
numbers[3] = 40
numbers[4] = 50
fmt.Printf("Type: %T\n", numbers)
fmt.Println("Element at index 2:", numbers[2])
fmt.Println("Length:", len(numbers))
fmt.Println("Capacity:", cap(numbers))
Array Initialization Methods
Go provides several ways to initialize arrays:
// Method 1: Explicit declaration with values
var data1 = [6]int{10, 20, 30, 40, 50, 60}
// Method 2: Short declaration
data2 := [4]string{"apple", "banana", "cherry", "date"}
// Method 3: Compiler counts elements automatically
data3 := [...]int{1, 2, 3}
// Method 4: Sparse initialization with specific indices
data4 := [6]int{0: 99, 3: 88}
// Result: [99 0 0 88 0 0]
Iterating Through Arrays
Using a traditional for loop:
scores := [5]int{85, 90, 78, 92, 88}
for i := 0; i < len(scores); i++ {
fmt.Printf("Index %d: %d\n", i, scores[i])
}
Using the range-based loop:
for idx, val := range scores {
fmt.Printf("Position %d holds value %d\n", idx, val)
}
Value Semantics
In Go, arrays are value types. When you assign one array to another, the entire contents are copied:
original := [3]int{1, 2, 3}
duplicate := original
duplicate[0] = 100
fmt.Println("Original:", original) // [1 2 3]
fmt.Println("Duplicate:", duplicate) // [100 2 3]
Multi-Dimensional Arrays
Go supports arrays with multiple dimensions:
matrix := [3][3]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
for _, row := range matrix {
fmt.Println(row)
}
Slices in Go
A slice is a dynamic, flexible view into an underlying array. Unlike arrays, slices can grow and shrink as needed.
Slice Declaration
// Empty slice
emptySlice := []int{}
// Slice with initial values
initialized := []int{10, 20, 30}
fmt.Printf("Type: %T, Value: %v\n", initialized, initialized)
Understanding Length vs Capacity
- Length: The number of elements currently stored in the slice
- Capacity: The total space available in the underlying array before reallocation is needed
Creating Slices with make
The make function allocates and initializes a slice with specified length and capacity:
make([]element_type, length, capacity)
buffer := make([]int, 3, 8)
fmt.Printf("Length: %d, Capacity: %d\n", len(buffer), cap(buffer))
fmt.Println("Initial values:", buffer)
buffer[0] = 42
buffer[1] = 73
buffer[2] = 99
fmt.Println("After assignment:", buffer)
Growing Slices with append
When elements exceed capacity, Go doubles the capacity (for larger slices, the growth factor is smaller):
dynamic := make([]int, 2, 4)
fmt.Printf("Before append - Length: %d, Capacity: %d\n", len(dynamic), cap(dynamic))
dynamic = append(dynamic, 1, 2, 3, 4, 5)
fmt.Printf("After append - Length: %d, Capacity: %d\n", len(dynamic), cap(dynamic))
fmt.Println("Contents:", dynamic)
Appending one slice to another requires the spread operator:
a := []int{1, 2}
b := []int{3, 4}
a = append(a, b...)
fmt.Println("Combined:", a)
Creating Slices from Arrays
Slices can be created as views into existing arrays:
fullArray := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
segment1 := fullArray[0:5] // Elements 0-4
segment2 := fullArray[3:7] // Elements 3-6
segment3 := fullArray[5:] // Elements 5-9
segment4 := fullArray[:] // All elements
fmt.Println(segment1) // [0 1 2 3 4]
fmt.Println(segment2) // [3 4 5 6]
Because slices reference the same underlying array, modifications affect both:
numbers := [5]int{10, 20, 30, 40, 50}
view := numbers[1:4]
numbers[2] = 99
fmt.Println("Array:", numbers) // [10 20 99 40 50]
fmt.Println("Slice:", view) // [20 99 40]
view[0] = 88
fmt.Println("Array:", numbers) // [10 88 99 40 50]
fmt.Println("Slice:", view) // [88 99 40]
Reference Semantics
Slices are reference types. Assigning one slice to another makes both point to the same underlying array:
alpha := []int{1, 2, 3}
beta := alpha
beta[0] = 100
fmt.Println("Alpha:", alpha) // [100 2 3]
fmt.Println("Beta:", beta) // [100 2 3]
Deep Copy with copy
To create an independent copy of a slice, use the built-in copy functon:
source := []int{1, 2, 3, 4, 5}
destination := make([]int, len(source))
copy(destination, source)
destination[0] = 99
fmt.Println("Source:", source) // [1 2 3 4 5]
fmt.Println("Destination:", destination) // [99 2 3 4 5]
Manual deep copy using append:
source := []int{10, 20, 30}
clone := make([]int, 0)
for _, v := range source {
clone = append(clone, v)
}
clone[1] = 200
fmt.Println("Source:", source) // [10 20 30]
fmt.Println("Clone:", clone) // [10 200 30]