package main import "fmt" /* How do we figure out where memory is allocated by Go? Not easily. The compiler will move data to heap whenever it decides to. This means you can pass a struct by copy (not by pointer), but the copy may not stay on the stack. When we have structures on the stack, there is always the danger that (for example), a function can return a pointer to the stacked struct, which becomes a dangling pointer when the stack is popped. Go doesn't keep track of ownership, because it has a garbage collector. So to avoid this kind of thing from happening, stacked data can get moved to the heap behind the scenes, so they can be garbage collected. Some helpful info can be found here https://medium.com/safetycultureengineering/an-overview-of-memory-management-in-go-9a72ec7c76a8 However, it appears to be the goal of Go to appeal to people who don't want to worry about memory allocation (aka java programmers). */ func cube(x int) int { // type is int -> int var y = x*x*x return y // one expects y (and x) to be on stack, and gets popped when cube returns. // what is returned is a copy of y } // But Go also has pointers, and you can write this: func rcube(x int) *int { var y = x*x*x return &y } // BUT WHERE THE - IS &y POINTING TO???!!! // Clearly, Go would not be memory-safe if this does what it would do // in C. In Rust, this won't compile. But Go allows this to happen // by "leaking" y onto the heap. y is copied from stack to the heap, // where it will be garbage collected when no longer needed. // Slogan of the day: "GO LEAKS" type Bigstruct struct { x int y int z int } func (self Bigstruct) reset() *Bigstruct { self.x = 0 self.y = 0 self.z = 0 return &self // clearly self is no longer on the stack } func (this *Bigstruct) resetp() { this.x = 0 this.y = 0 this.z = 0 } func copy(s Bigstruct) Bigstruct { return s } func main() { // gotta put { here, not on next line, refy := rcube(2) // same as var refy = rcube(2) fmt.Println(refy) // prints mem addr fmt.Println(*refy) // prints 8 S := Bigstruct{1,2,3} // this is on the stack, right? please? S.reset() fmt.Println(S) // still 1,2,3 because pass by copy, not pointer, but // where is the copy? on stack or heap? up to Go, not you T := S.reset() // T is a pointer to the copy that was passed to reset, fmt.Println(*T) // prints {0,0,0} S.resetp() fmt.Println(S) // now 0 0 0 var S2 = copy(S) // is this a real copy? (yes). S2.x = 9 fmt.Println("S.x is still ",S.x) // still 0 var S3 = &S2 S3.x = 7 fmt.Println("S2.x is ",S2.x) // 7 }//main /* To compile and run this program, download Go from https://go.dev/doc/tutorial/getting-started and follow the steps to 'go mod init' a project, then do 'go build .' to compile and 'go run .' to run. */