go/book/learninggo

Go - Arrays & Slices > Slices

Nil Slice

  • Declares a nil slice.
  • data is nil — it has no underlying array, length 0, and capacity 0.
  • len(data) == 0 and cap(data) == 0
  • data == nil → true
got := append([]Item(nil), someOtherSlice...)
var s []Item // Create nil slice
 
nils := []Item(nil) // Create nil slice
 
invalid := []Item(int) // 🔴 THIS IS NOT VALID

Since nil is a universal zero value for pointers, slices, maps, channels, interfaces, and functions, Go allows this([]Item(nil)) kind of conversion.

  • `nil` can be converted to any pointer, slice, map, channel, or function type.
  • So []Item(nil) is just the typed nil slice literal.

Empty Slice

  • Declares an empty but non-nil slice.
  • Backed by an empty array.
  • len(x) == 0, but it is not nil
  • x == nil → false

Why it matters

  • Checking for nil:
    if data == nil { fmt.Println("data is nil") } // true
    if x == nil   { fmt.Println("x is nil") }    // false
  • When marshaling to JSON:
    var data []int
    var x = []int{}
    
    json.Marshal(data) // null
    json.Marshal(x)    // []

So, use nil slice (var data []int) when you want to signal “no data”, and use []int{} when you mean “empty, but valid collection”.


Slicing Arrays

func main() {
	arr := [5]int{10, 20, 30, 40, 50}
	s := arr[1:4] // slice from index 1 to 3 → [20 30 40]
 
	s[0] = 99
 
	fmt.Println(arr) // [10 99 30 40 50] ← original array modified!
}

Copy Slice

import (
	"fmt"
	"reflect"
)
 
func main() {
	// Original slice
	original := []int{1, 2, 3, 4, 5}
 
	// Copy using append + nil
	copy1 := append([]int(nil), original...)
 
	// Copy using make + copy
	copy2 := make([]int, len(original))
	copy(copy2, original)
 
	// Copy using three-index slicing
	copy3 := append(original[:0:0], original...) // 👈 forces new backing array
 
	// Modify the copies
	copy1[0] = 100
	copy2[1] = 200
	copy3[2] = 300
 
	// Print all slices
	fmt.Println("Original:", original) // [1 2 3 4 5]
	fmt.Println("Copy 1  :", copy1)    // [100 2 3 4 5]
	fmt.Println("Copy 2  :", copy2)    // [1 200 3 4 5]
	fmt.Println("Copy 3  :", copy3)    // [1 2 300 4 5]
 
	// Compare each copy to original
	fmt.Println("original == copy1:", reflect.DeepEqual(original, copy1)) // false
	fmt.Println("original == copy2:", reflect.DeepEqual(original, copy2)) // false
	fmt.Println("original == copy3:", reflect.DeepEqual(original, copy3)) // false
 
	// Fresh untouched copy for equality test
	copy4 := append([]int(nil), original...)
	fmt.Println("original == copy4:", reflect.DeepEqual(original, copy4)) // true
}
 
MethodShares backing array?Notes
append([]int(nil), s...)❌Idiomatic and clean
make + copy❌Explicit and clear
append(s[:0:0], s...)❌Forcibly breaks backing array link
b := s✅Just a reference, not a copy