Конспект: Основы срезов (slices)
1. Определение и синтаксис
Срез — динамическая структура данных, обёртка над массивом.
Объявление
var slice []int // БЕЗ размера в []
Отличие от массива:
var array [3]int // Массив — с размером
var slice []int // Срез — без размера
2. Ключевые свойства
| Свойство | Описание |
|---|---|
| Динамическая структура | Можно добавлять/удалять элементы |
| Обёртка над массивом | Данные хранятся в массиве под капотом |
| Ссылочный тип | Копируется указатель, не данные |
| Может быть nil | В отличие от массива |
3. Nil-срез
var slice1 []int
fmt.Println(slice1) // []
fmt.Println(slice1 == nil) // true
Важно: Неинициализированный срез равен nil.
Массив vs Срез
var array [3]int
// array == nil // ❌ Ошибка компиляции — массив не может быть nil
var slice []int
fmt.Println(slice == nil) // ✅ true
4. Инициализация среза
Способ 1: Литерал
slice2 := []int{1, 2, 3, 4, 5}
fmt.Println(slice2) // [1 2 3 4 5]
fmt.Println(slice2 == nil) // false
Срез с данными не равен nil.
Способ 2: Пустой срез
slice3 := []int{}
fmt.Println(slice3) // []
fmt.Println(slice3 == nil) // false
fmt.Println(len(slice3)) // 0
Критическое различие:
var s1 []int // nil, len=0
s2 := []int{} // не nil, len=0
Оба выглядят как [], но:
s1— nil (указатель не инициализирован)s2— не nil (указатель на пустой массив)
Способ 3: Функция make()
slice4 := make([]int, 0)
fmt.Println(slice4 == nil) // false
Эквивалент:
slice3 := []int{} // Короткая форма
slice4 := make([]int, 0) // Явная форма
5. Сравнение: nil vs пустой срез
var nilSlice []int
emptySlice := []int{}
fmt.Println(nilSlice == nil) // true
fmt.Println(emptySlice == nil) // false
fmt.Println(len(nilSlice)) // 0
fmt.Println(len(emptySlice)) // 0
Визуально одинаковы, семантически различны:
| Срез | Состояние | nil? | len |
|---|---|---|---|
var s []int |
Не инициализирован | ✅ Да | 0 |
s := []int{} |
Инициализирован пустым | ❌ Нет | 0 |
s := make([]int, 0) |
Инициализирован пустым | ❌ Нет | 0 |
6. Копирование среза (ссылочный тип)
slice1 := []int{1, 2, 3}
slice2 := slice1 // Копируется только ссылка!
slice2[0] = 999
fmt.Println(slice1) // [999 2 3] — изменился!
fmt.Println(slice2) // [999 2 3]
Механизм:
slice1 ───┐
├──→ [999, 2, 3] (один массив в памяти)
slice2 ───┘
Отличие от массива:
array1 := [3]int{1, 2, 3}
array2 := array1 // Полная копия всех элементов
array2[0] = 999
fmt.Println(array1) // [1 2 3] — не изменился
fmt.Println(array2) // [999 2 3]
7. Полный пример
package main
import "fmt"
func main() {
// 1. Nil-срез
var s1 []int
fmt.Printf("s1: %v, nil=%t, len=%d\n", s1, s1 == nil, len(s1))
// s1: [], nil=true, len=0
// 2. Литерал с данными
s2 := []int{1, 2, 3, 4, 5}
fmt.Printf("s2: %v, nil=%t, len=%d\n", s2, s2 == nil, len(s2))
// s2: [1 2 3 4 5], nil=false, len=5
// 3. Пустой срез
s3 := []int{}
fmt.Printf("s3: %v, nil=%t, len=%d\n", s3, s3 == nil, len(s3))
// s3: [], nil=false, len=0
// 4. Через make
s4 := make([]int, 0)
fmt.Printf("s4: %v, nil=%t, len=%d\n", s4, s4 == nil, len(s4))
// s4: [], nil=false, len=0
}
8. Итоги
✅ Срез = динамическая обёртка над массивом
✅ Синтаксис: []T без указания размера
✅ Ссылочный тип — изменения видны через все копии
✅ Может быть nil — если не инициализирован
✅ []int{} ≠ nil, но len = 0 в обоих случаях
Ключевое правило:
var s []int → nil-срез
s := []int{} → пустой срез (не nil)
s := []int{1,2} → срез с данными
Следующий шаг: Функция make(), len(), cap(), операции со срезами.