Je suis nouveau dans Go et j'éprouve un peu de dissonance congitive entre la programmation basée sur la pile de style C où les variables automatiques vivent sur la pile et la mémoire allouée vit sur le tas et et la programmation basée sur la pile de style Python où le la seule chose qui vit sur la pile sont des références / pointeurs vers des objets sur le tas.
Pour autant que je sache, les deux fonctions suivantes donnent le même résultat:
func myFunction() (*MyStructType, error) {
var chunk *MyStructType = new(HeaderChunk)
...
return chunk, nil
}
func myFunction() (*MyStructType, error) {
var chunk MyStructType
...
return &chunk, nil
}
c'est-à-dire allouer une nouvelle structure et la renvoyer.
Si j'avais écrit cela en C, le premier aurait mis un objet sur le tas et le second l'aurait mis sur la pile. Le premier renverrait un pointeur vers le tas, le second renverrait un pointeur vers la pile, qui se serait évaporé au moment du retour de la fonction, ce qui serait une mauvaise chose.
Si je l'avais écrit en Python (ou dans de nombreux autres langages modernes à l'exception de C #), l'exemple 2 n'aurait pas été possible.
Je comprends que Go garbage collecte les deux valeurs, donc les deux formulaires ci-dessus conviennent.
Citer:
Notez que, contrairement à C, il est parfaitement correct de renvoyer l'adresse d'une variable locale; le stockage associé à la variable survit après le retour de la fonction. En fait, prendre l'adresse d'un littéral composite alloue une nouvelle instance à chaque fois qu'elle est évaluée, nous pouvons donc combiner ces deux dernières lignes.
Mais cela soulève quelques questions.
1 - Dans l'exemple 1, la structure est déclarée sur le tas. Qu'en est-il de l'exemple 2? Est-ce que cela est déclaré sur la pile de la même manière qu'il le serait en C ou est-ce que cela va aussi sur le tas?
2 - Si l'exemple 2 est déclaré sur la pile, comment reste-t-il disponible après le retour de la fonction?
3 - Si l'exemple 2 est effectivement déclaré sur le tas, comment se fait-il que les structures soient passées par valeur plutôt que par référence? Quel est l'intérêt des pointeurs dans ce cas?
Dans les deux cas, les implémentations actuelles de Go alloueraient de la mémoire pour un
struct
typeMyStructType
sur un tas et renverraient son adresse. Les fonctions sont équivalentes; la source asm du compilateur est la même.Tous les paramètres de fonction et de retour sont passés par valeur. La valeur du paramètre de retour avec type
*MyStructType
est une adresse.la source
Selon la FAQ de Go :
la source
Source: http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#stack_heap_vars
la source
Function1 et Function2 peuvent être des fonctions en ligne. Et la variable de retour ne s'échappera pas. Il n'est pas nécessaire d'allouer une variable sur le tas.
Mon exemple de code:
Selon la sortie de cmd:
production:
Si le compilateur est assez intelligent, F1 () F2 () F3 () peut ne pas être appelé. Parce que ça ne fait aucun moyen.
Peu importe si une variable est allouée sur un tas ou une pile, utilisez-la simplement. Protégez-le par mutex ou canal si nécessaire.
la source