Eu sou novo no Go e estou experimentando um pouco de dissonância congitiva entre a programação baseada em pilha no estilo C, em que variáveis automáticas vivem na pilha e alocam a vida útil da memória no heap e a programação baseada em pilha no estilo Python, em que o A única coisa que fica na pilha são referências / ponteiros para objetos na pilha.
Tanto quanto posso dizer, as duas funções a seguir fornecem a mesma saída:
func myFunction() (*MyStructType, error) {
var chunk *MyStructType = new(HeaderChunk)
...
return chunk, nil
}
func myFunction() (*MyStructType, error) {
var chunk MyStructType
...
return &chunk, nil
}
ou seja, aloque uma nova estrutura e retorne-a.
Se eu tivesse escrito isso em C, o primeiro teria colocado um objeto na pilha e o segundo o teria colocado na pilha. O primeiro retornaria um ponteiro para a pilha, o segundo retornaria um ponteiro para a pilha, que teria evaporado no momento em que a função retornasse, o que seria uma Coisa Ruim.
Se eu tivesse escrito em Python (ou em muitas outras linguagens modernas, exceto C #), o exemplo 2 não seria possível.
Entendo que o Go go coleta os dois valores, portanto, os dois formulários acima estão corretos.
Citar:
Observe que, ao contrário de C, é perfeitamente bom retornar o endereço de uma variável local; o armazenamento associado à variável sobrevive após o retorno da função. De fato, pegar o endereço de um literal composto aloca uma nova instância toda vez que é avaliada, para que possamos combinar essas duas últimas linhas.
Mas isso levanta algumas questões.
1 - No exemplo 1, a estrutura é declarada na pilha. E o exemplo 2? Isso é declarado na pilha da mesma maneira que seria em C ou também vai para a pilha?
2 - Se o exemplo 2 é declarado na pilha, como fica disponível após o retorno da função?
3 - Se o exemplo 2 é realmente declarado no heap, como as estruturas são passadas por valor e não por referência? Qual é o sentido dos ponteiros nesse caso?
Nos dois casos, as implementações atuais do Go alocariam memória para um
struct
tipoMyStructType
em um heap e retornariam seu endereço. As funções são equivalentes; a origem do compilador asm é a mesma.Todas as funções e parâmetros de retorno são passados por valor. O valor do parâmetro de retorno com o tipo
*MyStructType
é um endereço.fonte
De acordo com a FAQ da Go :
fonte
Fonte: http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#stack_heap_vars
fonte
Função1 e Função2 podem ser funções embutidas. E a variável de retorno não escapará. Não é necessário alocar variável na pilha.
Meu código de exemplo:
De acordo com a saída do cmd:
resultado:
Se o compilador for inteligente o suficiente, F1 () F2 () F3 () não poderá ser chamado. Porque não faz nenhum meio.
Não se preocupe se uma variável está alocada na pilha ou pilha, apenas use-a. Proteja-o por mutex ou canal, se necessário.
fonte