Dichiarare fetta o fare fetta?


99

In Go, qual è la differenza tra var s []inte s := make([]int, 0)?

Trovo che funzionino entrambi, ma qual è il migliore?


Il primo crea uno nilslice, mentre il secondo crea uno emptyslice (questa è la terminologia usata dal "Go in action book" ). Per evitare di postare la stessa risposta anche qui, è possibile controllare stackoverflow.com/a/45997533/1561148
tgogos

Risposte:


95

Oltre a fabriziom 's risposta , è possibile vedere altri esempi in ' Go fette: utilizzo e interni ', in cui un uso per []intè menzionato:

Poiché il valore zero di una slice ( nil) agisce come una slice di lunghezza zero , puoi dichiarare una variabile slice e poi aggiungerla in un ciclo:

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

Significa che, per aggiungere una slice, non devi prima allocare memoria: la nilslice p int[]è sufficiente come slice a cui aggiungere.


Perché pensi che farebbe un'allocazione? Cap è zero, quindi non viene allocato nulla con o senza make.
Arman Ordookhani,

1
@ArmanOrdookhani d'accordo. Trovo solo la dichiarazione var p []intpiù facile che usare make(che associo di più all'allocazione, anche se con un limite di 0, non allocherebbe nulla). In termini di leggibilità, preferisco non utilizzare makequi.
VonC

1
Sono più propenso a usare i letterali ovunque (ad esempio p := []int{}). Dato che di solito usiamo la :=sintassi per dichiarare la maggior parte delle variabili, è più naturale averla ovunque invece di avere eccezioni per le sezioni. Oltre a questo, cercare di pensare alle allocazioni di solito spinge le persone verso ottimizzazioni premature.
Arman Ordookhani

113

Semplice dichiarazione

var s []int

non alloca memoria e spunta a nil, while

s := make([]int, 0)

alloca memoria e spunta alla memoria a uno slice con 0 elementi.

Di solito, il primo è più idiomatico se non conosci la dimensione esatta del tuo caso d'uso.


Posso dire lo stesso per la mappa? var m map [string] int vs m: = make (map [string] int)? Grazie.
joshua

11
Nah, hai bisogno di makemappe, perché anche un vuoto ha mapbisogno di spazio assegnato per qualche contabilità.
giorni

11
Se devi restituire uno slice con 0 elementi (invece di 'nil'), make è l'uso corretto.
Jess

6
Se stai creando un'API e restituisci un array come risposta, l'uso del modulo dichiarativo verrà restituito nilnel caso in cui la tua slice non abbia alcun elemento, piuttosto che un array vuoto. Tuttavia, se makeviene utilizzato per creare la sezione, verrà restituito un array vuoto, che in genere è l'effetto desiderato.
robinmitra

6
Come accennato in un commento su questa risposta: stackoverflow.com/a/29164565/1311538 , ci sono differenze quando si tenta di fare cose come il marshalling di json. Il marshalling della slice nil ( var s []int) produrrà null, mentre il marshalling della slice vuota ( s := make([]int, 0)) produrrà l'atteso[]
asgaines

8

Ho appena trovato una differenza. Se usi

var list []MyObjects

e poi codifichi l'output come JSON, ottieni null.

list := make([]MyObjects, 0)

risultati []come previsto.


yah, quest'ultimo è abbastanza utile quando vogliamo rispondere con [] array invece di null
Nhan Tran,

4

Un po 'più completamente (un altro argomento in make) esempio:

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

Su:

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

O con tipo dinamico di slice:

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

Su:

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

2
Buoni esempi. +1
VonC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.