Nil Slice
- Declares a nil slice.
dataisnil— it has no underlying array, length 0, and capacity 0.len(data) == 0andcap(data) == 0data == 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 VALIDSince 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 nilx == 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
}
| Method | Shares 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 |