В Go zero value для среза — это nil
. Это означает, что объявление среза без инициализации создает nil-срез:
var s []int // s == nil
Характеристики nil-среза:
fmt.Println(len(s)) // 0
fmt.Println(cap(s)) // 0
fmt.Println(s == nil) // true
Все операции, которые не требуют модификации памяти, работают с nil-срезом:
var s []int
// Получение длины и емкости
fmt.Println(len(s)) // 0
fmt.Println(cap(s)) // 0
// Итерация по срезу (не выполнит итераций)
for i, v := range s {
fmt.Println(i, v) // Не выполнится
}
// Чтение элемента (паника!)
// v := s[0] // panic: runtime error: index out of range [0] with length 0
Единственная операция модификации, которая работает с nil-срезом:
var s []int
s = append(s, 1, 2, 3) // Создается новый массив
fmt.Println(s) // [1 2 3]
Операции взятия среза работают с nil-срезом:
var s []int
subSlice := s[:] // Создает новый nil-срез
fmt.Println(subSlice == nil) // true
Функция copy работает, но ничего не копирует:
var s []int
dst := make([]int, 3)
n := copy(dst, s) // n == 0, dst останется [0, 0, 0]
var s []int
v := s[0] // panic: index out of range
var s []int
s[0] = 1 // panic: index out of range
var s1 []int
s2 := []int{}
fmt.Println(s1 == s2) // Ошибка компиляции: slice can only be compared to nil
func findEvenNumbers(nums []int) []int {
var result []int
for _, n := range nums {
if n%2 == 0 {
result = append(result, n)
}
}
return result // Вернет nil если четных чисел нет
}
func GetUserRoles(userID int) []string {
if userID == 0 {
return nil // Явный сигнал отсутствия данных
}
return []string{"user"}
}
// Лучше чем empty slice ([]int{}) когда данных нет
var activeConnections []*Connection // nil пока нет соединений
var nilSlice []int // len=0, cap=0, nil
emptySlice := []int{} // len=0, cap=0, not nil
zeroSlice := make([]int, 0) // len=0, cap=0, not nil
Ключевые различия:
zero value для среза в Go — это nil. С nil-срезом безопасно можно выполнять операции чтения метаданных (len, cap), итерации, append и slicing. Индексация и модификация элементов вызовут панику. Nil-срезы полезны как сигнал отсутствия данных и для оптимизации памяти, но важно понимать их отличие от пустых срезов.