Пустой срез vs. nil-срез в Go

Как вы знаете, объявленная без инициализации переменная в Go автоматически получает нулевое значение соответствующего типа:

var num int    // 0
var str string // ""
var flag bool  // false

Для среза нулевое значение — nil:

var snil []int
// []int(nil)

С другой стороны, бывает инициализированный, но пустой срез:

sempty := []int{}
// or
// sempty = make([]int, 0)

Это разные значения, которые не равны между собой:

reflect.DeepEqual(snil, sempty)
// false

И в то же время, пустой срез и nil-срез почти всегда взаимозаменямы:

len(snil) // 0
cap(snil) // 0
snil = append(snil, 1) // []int{1}

len(sempty) // 0
cap(sempty) // 0
sempty = append(sempty, 1) // []int{1}

reflect.DeepEqual(snil, sempty)
// true

Почти всегда ваш код не должен делать разницы между пустым и nil-срезом.

Одно из заметных исключений — работа с JSON, при которой мы часто хотим отличать null (nil-срез) и [] (пустой срез).

★ Подписывайтесь на новые заметки.