Объявить срез или сделать срез?

99

В Go в чем разница между var s []intи s := make([]int, 0)?

Я считаю, что оба работают, но какой из них лучше?

Ван И
источник
Первый создает nilсрез, а второй - emptyсрез (это терминология, используемая в «Книге действий» ). Чтобы не публиковать здесь тот же ответ, вы можете проверить stackoverflow.com/a/45997533/1561148
tgogos 01

Ответы:

95

В дополнении к fabriziom «s ответа , вы можете увидеть больше примеров на„ Go Ломтиках: использование и внутренние органы “, где использование для []intупоминаются:

Поскольку нулевое значение slice ( nil) действует как срез нулевой длины , вы можете объявить переменную среза и затем добавить к ней в цикле:

// Filter returns a new slice holding only
// the elements of s that satisfy f()
func Filter(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

Это означает, что для добавления к срезу вам не нужно сначала выделять память: nilсреза p int[]достаточно в качестве среза для добавления.

VonC
источник
Почему вы думаете, что это будет распределение? Cap равен нулю, поэтому ничего не выделяется с make или без него.
Арман Ордухани,
1
@ArmanOrdookhani Согласен. Я просто считаю, что объявление var p []intпроще, чем использовать make(которое я больше связываю с распределением, хотя с ограничением 0 оно ничего не выделяет). Что касается удобочитаемости, я предпочитаю не использовать makeздесь.
VonC
1
Я больше использую литералы везде (например p := []int{}). Поскольку мы обычно используем :=синтаксис для объявления большинства переменных, более естественно иметь его везде, вместо того, чтобы иметь исключения для срезов. Помимо этого попытки думать о распределении обычно подталкивают людей к преждевременной оптимизации.
Арман Ордоохани,
113

Простое объявление

var s []int

не выделяет память и sуказывает на nil, в то время как

s := make([]int, 0)

выделяет память и sуказывает в памяти на срез с 0 элементами.

Обычно первый вариант более идиоматичен, если вы не знаете точного размера вашего варианта использования.

фабрициоМ
источник
Могу ли я сказать то же самое о карте? var m map [строка] int vs m: = make (map [строка] int)? Спасибо.
Джошуа
11
Нет, вам нужны makeкарты, потому что даже пустое место mapтребует места для какой-то бухгалтерии.
twotwotwo,
11
Если вам нужно вернуть фрагмент с 0 элементами (вместо nil), правильным использованием будет make.
Джесс
6
Если вы создаете API и возвращаете массив в качестве ответа, использование декларативной формы будет возвращено nilв случае, если ваш фрагмент не имеет никакого элемента, а не пустой массив. Однако, если makeон используется для создания среза, вместо него будет возвращен пустой массив, что обычно является желаемым эффектом.
robinmitra
6
Как упоминалось в комментарии к этому ответу: stackoverflow.com/a/29164565/1311538 , существуют различия при попытке сделать такие вещи, как маршалинг json. Маршалинг nil slice ( var s []int) произведет null, в то время как маршалинг пустого slice ( s := make([]int, 0)) произведет ожидаемый результат[]
asgaines
8

Только что нашел разницу. Если вы используете

var list []MyObjects

а затем вы кодируете вывод как JSON, вы получаете null.

list := make([]MyObjects, 0)

приводит []к ожидаемым результатам.

Стив Ханов
источник
да, последнее очень полезно, когда мы хотим
ответить
4

Немного более полный (еще один аргумент make) пример:

slice := make([]int, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Вне:

length:  2 - capacity 5 - content:  [0 0]

Или с динамическим типом slice:

slice := make([]interface{}, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Вне:

length:  2 - capacity 5 - content:  [<nil> <nil>]
Беньямин Джафари
источник
2
Хорошие примеры. +1
VonC