Ответ
В Go существует несколько основных способов создания слайса, каждый из которых подходит для определенных задач. Рассмотрим три главных подхода.
1. Объявление через var
(нулевое значение)
Создает nil
-слайс. Это не то же самое, что пустой слайс.
- Синтаксис:
var s []int
- Состояние:
s == nil
,len(s) == 0
,cap(s) == 0
. - Память: Указатель на базовый массив равен
nil
. Память под элементы не выделяется. - Особенность: Несмотря на то что слайс
nil
, к нему можно безопасно применять функциюappend
. Go автоматически выделит память при первом добавлении элемента.
2. Использование литерала слайса
Создает слайс и сразу инициализирует его значениями.
- Синтаксис:
s := []int{}
— пустой слайс (неnil
).s := []int{1, 2, 3}
— слайс с начальными элементами.
- Состояние:
- Для
[]int{}
:s != nil
,len(s) == 0
,cap(s) == 0
. - Для
[]int{1, 2, 3}
:len(s) == 3
,cap(s) == 3
.
- Для
- Память: Создается новый базовый массив, содержащий указанные элементы.
3. Использование функции make
Лучший способ, когда вы заранее знаете необходимый размер слайса. Это позволяет избежать многократных перераспределений памяти при использовании append
, что повышает производительность.
- Синтаксис:
make([]T, length)
— создает слайс с длинойlength
и емкостьюlength
.make([]T, length, capacity)
— создает слайс с длинойlength
и емкостьюcapacity
.
- Состояние (для
make([]int, 3, 5)
):len(s) == 3
,cap(s) == 5
. Слайс будет[0, 0, 0]
. - Память: Выделяется базовый массив размером
capacity
. Элементы инициализируются нулевыми значениями для их типа (0 дляint
,false
дляbool
, и т.д.).
Сводный пример:
package main
import "fmt"
func main() {
// 1. var (nil-слайс)
var s1 []int
fmt.Printf("s1: val=%v, is_nil=%t, len=%d, cap=%dn", s1, s1 == nil, len(s1), cap(s1))
s1 = append(s1, 100)
fmt.Printf("s1 after append: val=%v, is_nil=%t, len=%d, cap=%dnn", s1, s1 == nil, len(s1), cap(s1))
// 2. Литерал (пустой, не nil)
s2 := []int{}
fmt.Printf("s2: val=%v, is_nil=%t, len=%d, cap=%dnn", s2, s2 == nil, len(s2), cap(s2))
// 3. Литерал (с данными)
s3 := []int{1, 2, 3}
fmt.Printf("s3: val=%v, is_nil=%t, len=%d, cap=%dnn", s3, s3 == nil, len(s3), cap(s3))
// 4. make
s4 := make([]int, 3, 5)
fmt.Printf("s4: val=%v, is_nil=%t, len=%d, cap=%dn", s4, s4 == nil, len(s4), cap(s4))
}
/*
Вывод:
s1: val=[], is_nil=true, len=0, cap=0
s1 after append: val=[100], is_nil=false, len=1, cap=1
s2: val=[], is_nil=false, len=0, cap=0
s3: val=[1 2 3], is_nil=false, len=3, cap=3
s4: val=[0 0 0], is_nil=false, len=3, cap=5
*/
Когда что использовать?
var s []T
: Когда вы не знаете начальный размер и будете наполнять слайс динамически (например, с помощьюappend
в цикле).s := []T{...}
: Когда вы заранее знаете точные значения, которые должны быть в слайсе.make([]T, len, cap)
: Когда вы знаете необходимый размер или емкость слайса, но не его конкретные значения. Это самый производительный способ для таких случаев.