Déclarer une tranche ou faire une tranche?

99

Dans Go, quelle est la différence entre var s []intet s := make([]int, 0)?

Je trouve que les deux fonctionnent, mais lequel est le meilleur?

Wang Yi
la source
Le premier crée une niltranche, tandis que le second crée une emptytranche (c'est la terminologie utilisée par le "Go in action book" ). Pour éviter de publier la même réponse ici aussi, vous pouvez consulter stackoverflow.com/a/45997533/1561148
tgogos

Réponses:

95

En plus de la réponse de fabriziom , vous pouvez voir plus d'exemples sur " Go Slices: usage and internals ", où une utilisation pour est mentionnée:[]int

Étant donné que la valeur zéro d'une tranche ( nil) agit comme une tranche de longueur nulle , vous pouvez déclarer une variable de tranche, puis y ajouter une boucle:

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

Cela signifie que, pour ajouter à une tranche, vous n'avez pas à allouer de mémoire en premier: la niltranche p int[]est suffisante en tant que tranche à ajouter.

VonC
la source
Pourquoi pensez-vous qu'il ferait une allocation? Le plafond est égal à zéro, donc rien n'est alloué avec ou sans make.
Arman Ordookhani le
1
@ArmanOrdookhani D'accord. Je trouve juste la déclaration var p []intplus facile que d'utiliser make(que j'associe davantage à l'allocation, même si avec un plafond de 0, elle n'allouerait rien). En terme de lisibilité, je préfère ne pas utiliser makeici.
VonC le
1
Je suis plus vers l'utilisation de littéraux partout (par exemple p := []int{}). Puisque nous utilisons généralement la :=syntaxe pour déclarer la plupart des variables, il est plus naturel de l'avoir partout au lieu d'avoir des exceptions pour les tranches. En dehors de cela, essayer de penser aux allocations pousse généralement les gens vers des optimisations prématurées.
Arman Ordookhani le
113

Déclaration simple

var s []int

n'alloue pas de mémoire et spointe vers nil, tandis que

s := make([]int, 0)

alloue de la mémoire et spointe vers la mémoire une tranche avec 0 élément.

Habituellement, le premier est plus idiomatique si vous ne connaissez pas la taille exacte de votre cas d'utilisation.

fabrizioM
la source
Puis-je dire la même chose pour la carte? var m map [chaîne] int vs m: = make (map [string] int)? Merci.
joshua
11
Non, vous avez besoin de makecartes, car même un mapespace vide a besoin d'un espace alloué pour une comptabilité.
twotwotwo
11
Si vous avez besoin de retourner une tranche avec 0 élément (au lieu de «nil»), make est l'utilisation correcte.
Jess
6
Si vous construisez une API et que vous renvoyez un tableau comme réponse, l'utilisation du formulaire déclaratif reviendra nilau cas où votre tranche n'aurait aucun élément, plutôt qu'un tableau vide. Cependant, si makeest utilisé pour créer la tranche, un tableau vide sera renvoyé à la place, ce qui est généralement l'effet souhaité.
robinmitra
6
Comme mentionné dans un commentaire sur cette réponse: stackoverflow.com/a/29164565/1311538 , il existe des différences lors de la tentative de faire des choses comme le marshaling json. Le marshaling de la tranche nulle ( var s []int) produira null, tandis que le marshaling de la tranche vide ( s := make([]int, 0)) produira le résultat attendu[]
asgaines
8

Je viens de trouver une différence. Si tu utilises

var list []MyObjects

puis vous encodez la sortie en JSON, vous obtenez null.

list := make([]MyObjects, 0)

résultats []comme prévu.

Steve Hanov
la source
yah, ce dernier est assez utile lorsque nous voulons répondre avec [] array au lieu de null
Nhan Tran
4

Un peu plus complètement (un autre argument dans make) exemple:

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

En dehors:

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

Ou avec type dynamique de slice:

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

En dehors:

length:  2 - capacity 5 - content:  [<nil> <nil>]
Benyamin Jafari
la source
2
Bons exemples. +1
VonC