Soy nuevo en Go y estoy experimentando un poco de disonancia congitiva entre la programación basada en pila de estilo C donde las variables automáticas viven en la pila y la memoria asignada vive en el montón y la programación basada en pila de estilo Python donde Lo único que vive en la pila son referencias / punteros a objetos en el montón.
Por lo que puedo decir, las dos funciones siguientes dan la misma salida:
func myFunction() (*MyStructType, error) {
var chunk *MyStructType = new(HeaderChunk)
...
return chunk, nil
}
func myFunction() (*MyStructType, error) {
var chunk MyStructType
...
return &chunk, nil
}
es decir, asignar una nueva estructura y devolverla.
Si hubiera escrito eso en C, el primero habría puesto un objeto en el montón y el segundo lo habría puesto en la pila. El primero devolvería un puntero al montón, el segundo devolvería un puntero a la pila, que se habría evaporado para cuando la función hubiera regresado, lo que sería una mala cosa.
Si lo hubiera escrito en Python (o en muchos otros lenguajes modernos, excepto C #), el ejemplo 2 no hubiera sido posible.
Entiendo que Go basura recolecta ambos valores, por lo que las dos formas anteriores están bien.
Citar:
Tenga en cuenta que, a diferencia de C, está perfectamente bien devolver la dirección de una variable local; el almacenamiento asociado con la variable sobrevive después de que vuelve la función. De hecho, tomar la dirección de un literal compuesto asigna una nueva instancia cada vez que se evalúa, por lo que podemos combinar estas dos últimas líneas.
Pero plantea un par de preguntas.
1 - En el ejemplo 1, la estructura se declara en el montón. ¿Qué pasa con el ejemplo 2? ¿Se declara eso en la pila de la misma manera que lo estaría en C o también va en el montón?
2 - Si el ejemplo 2 se declara en la pila, ¿cómo permanece disponible después de que la función regrese?
3 - Si el ejemplo 2 se declara realmente en el montón, ¿cómo es que las estructuras se pasan por valor en lugar de por referencia? ¿Qué sentido tienen los punteros en este caso?
En ambos casos, las implementaciones actuales de Go asignarían memoria para un
struct
tipoMyStructType
en un montón y devolverían su dirección. Las funciones son equivalentes; la fuente del compilador asm es la misma.Todos los parámetros de función y retorno se pasan por valor. El valor del parámetro de retorno con tipo
*MyStructType
es una dirección.fuente
De acuerdo con las preguntas frecuentes de Go :
fuente
Fuente: http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#stack_heap_vars
fuente
Function1 y Function2 pueden ser funciones en línea. Y la variable de retorno no escapará. No es necesario asignar variables en el montón.
Mi código de ejemplo:
Según la salida de cmd:
salida:
Si el compilador es lo suficientemente inteligente, F1 () F2 () F3 () puede no ser llamado. Porque no tiene medios.
No importa si una variable está asignada en el montón o en la pila, solo utilícela. Protéjalo con mutex o canal si es necesario.
fuente