Правильный способ инициализации пустого среза

227

Чтобы объявить пустой фрагмент с нефиксированным размером, лучше сделать:

mySlice1 := make([]int, 0)

или:

mySlice2 := []int{}

Просто интересно, какой из них правильный.

eouti
источник
2
Вы говорите «нефиксированный размер», но срезы никогда не имеют фиксированного размера. Если вы не имеете в виду с нулевой емкостью. Обратите внимание, если у вас есть идея / предположение / подсказка о том, какая емкость вам может понадобиться, тогда лучше использовать версию с тремя аргументами. Например, чтобы построить кусок ключей карты:keys := make([]int, 0, len(m)); for k, v := range m { keys := append(keys,k) }
Дейв C
1
Возможный дубликат объявления среза или создания среза?
пользователь

Ответы:

272

Две альтернативы, которые вы дали, семантически идентичны, но использование make([]int, 0)приведет к внутреннему вызову runtime.makeslice (Go 1.14).

У вас также есть возможность оставить его со nilзначением:

var myslice []int

Как написано в блоге Golang.org :

Нулевой срез функционально эквивалентен срезу нулевой длины, даже если он ничего не указывает. Он имеет нулевую длину и может быть добавлен с выделением.

Однако, nilсрез будет json.Marshal()в "null"то время как пустой срез будет "[]"маршалировать, как указано @farwayer.

Ни один из вышеперечисленных параметров не приведет к выделению, как указывает @ArmanOrdookhani.

Anisus
источник
4
Также
упомяните в
106
Будьте осторожны: json.Marshal()вернется nullза var myslice []intи []для инициализированного срезаmyslice := []int{}
farwayer
10
Также будьте осторожны: reflect.DeepEqualделает различие между нулевыми дольки и не-нулевыми ломтиков: a := []int{}, var b []int,reflect.DeepEqual(a, b) // returns false
asgaines
1
Почему вы думаете, что это сделает распределение? Цоколь равен нулю, поэтому ничего не выделяется. Все указатели на объекты нулевой длины указывают на одно и то же место в памяти: play.golang.org/p/MPOKKl_sYvw
Арман Ордухани
1
@ArmanOrdookhani Вы правы. Я попробовал это, и я также узнал, что был не прав с моим предположением об идентичных инструкциях по сборке. Исправлена!
ANisus
65

Они эквивалентны. Смотрите этот код:

mySlice1 := make([]int, 0)
mySlice2 := []int{}
fmt.Println("mySlice1", cap(mySlice1))
fmt.Println("mySlice2", cap(mySlice2))

Вывод:

mySlice1 0
mySlice2 0

Оба среза имеют 0емкость, которая подразумевает, что оба среза имеют 0длину (не может быть больше емкости), что означает, что оба среза не имеют элементов. Это означает, что 2 среза идентичны в каждом аспекте.

Смотрите похожие вопросы:

Какой смысл иметь нулевой ломтик и пустой ломтик в Голанге?

ноль ломтиков против не ноль ломтиков против пустых ломтиков на языке Go

icza
источник
46

Как дополнение к ответу @ANisus ...

ниже приведена информация из книги « Действуй», о которой, я думаю, стоит упомянуть:

Разница между nil& emptyломтиками

Если мы думаем о срезе, как это:

[pointer] [length] [capacity]

затем:

nil slice:   [nil][0][0]
empty slice: [addr][0][0] // points to an address

ноль ломтик

Они полезны, когда вы хотите представить фрагмент, который не существует, например, когда возникает исключение в функции, которая возвращает фрагмент.

// Create a nil slice of integers.
var slice []int

пустой ломтик

Пустые фрагменты полезны, когда вы хотите представить пустую коллекцию, например, когда запрос к базе данных возвращает ноль результатов.

// Use make to create an empty slice of integers.
slice := make([]int, 0)

// Use a slice literal to create an empty slice of integers.
slice := []int{}

Независимо от того, используете ли вы нулевой ломтик или пустой кусок, встроенные в функции append, lenи capработать так же.


Пример игровой площадки :

package main

import (
    "fmt"
)

func main() {

    var nil_slice []int
    var empty_slice = []int{}

    fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
    fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))

}

печатает:

true 0 0
false 0 0
tgogos
источник
Можем ли мы получить адрес пустого фрагмента за один шаг, используя make?
Симин Цзе
Если мы посмотрим на сигнатуру функции , makeкажется, не возвращает адрес. Я считаю, что вы не можете сделать это за один шаг.
tgogos
13

Пустой срез и нулевой срез инициализируются по-разному в Go:

var nilSlice []int 
emptySlice1 := make([]int, 0)
emptySlice2 := []int{}

fmt.Println(nilSlice == nil)    // true
fmt.Println(emptySlice1 == nil) // false
fmt.Println(emptySlice2 == nil) // false

Что касается всех трех ломтиков, len и cap равны 0.

Joe.CK
источник
make([]int, 0)является лучшим, потому что Jetbrains GoLand не жалуется на то, что он «ненужен», как это имеет место в случае []int{}. Это полезно при написании юнит-тестов.
Анджей Реманн