Declarar fatia ou fazer fatia?


99

Em Go, qual é a diferença entre var s []inte s := make([]int, 0)?

Acho que ambos funcionam, mas qual é o melhor?


O primeiro cria um nilslice, enquanto o segundo cria um emptyslice (esta é a terminologia usada pelo "Go in action book" ). Para evitar postar a mesma resposta aqui também, você pode verificar stackoverflow.com/a/45997533/1561148
tgogos 01 de

Respostas:


95

Além fabriziom 's resposta , você pode ver mais exemplos em ' Go Slices: uso e internos ', onde um uso para []inté mencionado:

Uma vez que o valor zero de uma fatia ( nil) atua como uma fatia de comprimento zero , você pode declarar uma variável de fatia e, em seguida, anexá-la em um loop:

// 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
}

Isso significa que, para anexar a uma fatia, você não precisa alocar memória primeiro: a nilfatia p int[]é suficiente como uma fatia a ser adicionada.


Por que você acha que faria uma alocação? O limite é zero, então nada é alocado com ou sem make.
Arman Ordookhani

1
@ArmanOrdookhani Concordo. Eu apenas acho a declaração var p []intmais fácil do que usar make(que eu associo mais com alocação, embora com um limite 0, ela não alocaria nada). Em termos de legibilidade, prefiro não usar makeaqui.
VonC

1
Estou mais voltado para o uso de literais em todos os lugares (por exemplo p := []int{}). Como geralmente usamos :=sintaxe para declarar a maioria das variáveis, é mais natural tê-la em todos os lugares em vez de ter exceções para fatias. Fora isso, tentar pensar em alocações geralmente leva as pessoas a otimizações prematuras.
Arman Ordookhani

113

Declaração simples

var s []int

não aloca memória e saponta para nil, enquanto

s := make([]int, 0)

aloca memória e saponta para a memória para uma fatia com 0 elementos.

Normalmente, o primeiro é mais idiomático se você não souber o tamanho exato do seu caso de uso.


Posso dizer o mesmo para o mapa? var m map [string] int vs m: = make (map [string] int)? Obrigado.
joshua

11
Nah, você precisa de makemapas, porque mesmo um vazio mapprecisa de espaço alocado para alguma contabilidade.
twotwotwo

11
Se você precisar retornar uma fatia com 0 elementos (em vez de 'nil'), faça o uso correto.
Jess de

6
Se você estiver construindo uma API e retornar um array como resposta, o uso da forma declarativa retornará nilcaso seu slice não tenha nenhum elemento, em vez de um array vazio. No entanto, se makefor usado para criar a fatia, um array vazio será retornado, o que geralmente é o efeito desejado.
robinmitra de

6
Conforme mencionado em um comentário sobre esta resposta: stackoverflow.com/a/29164565/1311538 , há diferenças ao tentar fazer coisas como empacotamento json. O empacotamento da fatia nula ( var s []int) produzirá null, enquanto o empacotamento da fatia vazia ( s := make([]int, 0)) produzirá o esperado[]
asgaines

8

Acabei de encontrar uma diferença. Se você usar

var list []MyObjects

e então você codifica a saída como JSON, você obtém null.

list := make([]MyObjects, 0)

resulta []conforme o esperado.


sim, o último é bastante útil quando queremos uma resposta com array [] em vez de null
Nhan Tran

4

Exemplo um pouco mais completo (mais um argumento make):

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

Fora:

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

Ou com tipo dinâmico de slice:

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

Fora:

length:  2 - capacity 5 - content:  [<nil> <nil>]

2
Bons exemplos. +1
VonC
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.