Jestem nowy w Go i doświadczam nieco zbieżnego dysonansu między programowaniem opartym na stosie w stylu C, w którym zmienne automatyczne żyją na stosie i przydzieloną pamięć na stercie i programowaniem opartym na stosie w stylu Pythona, gdzie jedyną rzeczą, która żyje na stosie, są odniesienia / wskaźniki do obiektów na stercie.
O ile wiem, dwie następujące funkcje dają ten sam wynik:
func myFunction() (*MyStructType, error) {
var chunk *MyStructType = new(HeaderChunk)
...
return chunk, nil
}
func myFunction() (*MyStructType, error) {
var chunk MyStructType
...
return &chunk, nil
}
tj. przydziel nową strukturę i zwróć ją.
Gdybym napisał to w C, pierwszy umieściłby obiekt na stercie, a drugi na stosie. Pierwsza zwróciłaby wskaźnik do stosu, druga zwróciłaby wskaźnik do stosu, który wyparowałby do czasu zwrócenia funkcji, co byłoby złą rzeczą.
Gdybym napisał to w Pythonie (lub wielu innych współczesnych językach oprócz C #), przykład 2 nie byłby możliwy.
Rozumiem, że śmieci Go gromadzą obie wartości, więc obie powyższe formy są w porządku.
Cytować:
Zauważ, że w przeciwieństwie do C, zwrócenie adresu zmiennej lokalnej jest całkowicie OK; pamięć związana ze zmienną przetrwa po powrocie funkcji. W rzeczywistości pobranie adresu literału złożonego przydziela nowe wystąpienie za każdym razem, gdy jest ono oceniane, więc możemy połączyć te dwie ostatnie linie.
Ale rodzi kilka pytań.
1 - W przykładzie 1 struktura jest zadeklarowana na stercie. A co z przykładem 2? Czy jest to zadeklarowane na stosie w taki sam sposób, w jaki byłoby to w C, czy też trafia na stos?
2 - Jeśli przykład 2 jest zadeklarowany na stosie, w jaki sposób pozostaje on dostępny po powrocie funkcji?
3 - Jeśli przykład 2 jest faktycznie zadeklarowany na stercie, w jaki sposób struktury są przekazywane przez wartość, a nie przez odwołanie? Jaki jest sens wskazówek w tym przypadku?
W obu przypadkach obecne implementacje Go przydzielałyby pamięć dla
struct
typuMyStructType
na stercie i zwracały jej adres. Funkcje są równoważne; źródło asm kompilatora jest takie samo.Wszystkie parametry funkcji i zwracane są przekazywane przez wartość. Wartość parametru zwracanego z typem
*MyStructType
to adres.źródło
Zgodnie z FAQ Go :
źródło
Źródło: http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#stack_heap_vars
źródło
Funkcja 1 i Funkcja 2 mogą być funkcjami wbudowanymi. Zmienna zwracana nie ucieknie. Nie jest konieczne przydzielanie zmiennej na stercie.
Mój przykładowy kod:
Zgodnie z wyjściem cmd:
wynik:
Jeśli kompilator jest wystarczająco inteligentny, nie można wywołać F1 () F2 () F3 () . Ponieważ to nic nie da.
Nie przejmuj się tym, czy zmienna jest przydzielona na stercie czy na stosie, po prostu jej użyj. W razie potrzeby chroń go za pomocą muteksu lub kanału.
źródło