web-dev-qa-db-fra.com

Les tranches de golang sont-elles passées par valeur?

À Golang, j'essaie de créer une fonction de tranche de brouillage pour résoudre le problème de mon commis voyageur. Ce faisant, j'ai remarqué que lorsque je commençais à éditer la tranche, la fonction de brouillage était différente à chaque fois que je la transmettais.

Après un certain débogage, j'ai découvert que c'était à cause de ma modification de la tranche dans la fonction. Mais puisque Golang est supposé être un langage "passe-à-valeur", comment est-ce possible?

https://play.golang.org/p/mMivoH0TuV

J'ai fourni un lien de terrain de jeu pour montrer ce que je veux dire. En supprimant la ligne 27, vous obtenez une sortie différente de celle laissée, cela ne devrait pas faire de différence, car la fonction est supposée créer sa propre copie de la tranche lorsqu'elle est transmise en tant qu'argument.
Quelqu'un peut-il expliquer le phénomène?

32
duck

Oui, tout dans Go est passé par valeur. Des tranches aussi. Mais une valeur de tranche est un en-tête , décrivant une section contiguë d'un tableau de sauvegarde, et une valeur de tranche ne contient qu'un pointeur sur le tableau où se trouvent les éléments. effectivement stocké. La valeur de la tranche n'inclut pas ses éléments (contrairement aux tableaux).

Ainsi, lorsque vous transmettez une tranche à une fonction, une copie de cet en-tête, y compris le pointeur, sera dirigée vers le même tableau de sauvegarde. La modification des éléments de la tranche implique la modification des éléments du tableau de sauvegarde. Ainsi, toutes les tranches qui partagent le même tableau de sauvegarde "observent" le changement.

Pour voir le contenu d'un en-tête de tranche, consultez le reflect.SliceHeader type:

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

Voir la question connexe/possible en double: Le paramètre de fonction Golang est-il passé en tant que copie sur écriture?

Lire le message de blog: Go Slices: utilisation et internes

81
icza