23

What is the best way to "build" an object.

Leme write some code:

type Car struct {
   Wheels int
   Doors  int
} 

This cars are stored somewhere, somehow. So should my interface be the type of

func (s Store) GetCar() *Car

or should I make it

func (s Store) GetCar(*Car)

and pass a reference to a variable?

Im looking for some sort of rule of thumb.

Thanks!

3
  • 3
    Are you comparing to a language like C where the return value is often passed as a pointer in the function arguments? Since Go has multiple return values, and safe pointer escape analysis, there is usually no reason to ever do that. Commented Jun 29, 2017 at 13:57
  • 1
    If you've read any of the existing Go corpus that's available, you'll find the "output parameter" style (second example) is never used in Go. Commented Jun 29, 2017 at 14:01
  • Where in the standard library (as a reference of how to write Go code) did you see an API of the form func (s Store) GetCar(*Car)? Almost nowhere. That should answer your question. (For the nitpickers: Yes, some low-level functions expose such API to allow reduction of allocation.) Commented Jun 29, 2017 at 14:35

4 Answers 4

21

Go manages the heap/stack, keeping track when the reference goes outside of scope. So, you can return the pointer without any worries.

func (s *Store) GetCar() *Car {
    return &Car{Store: s}
}
Sign up to request clarification or add additional context in comments.

2 Comments

Ok, so passing a reference as a parameter would be better if I have a interface{} type where idk the structure, ie: mgo where you pass a reference to your struct that the would be populated? (more like a generics way where you dont know what are you gonna return) or in case I want to make some instance manipulation
I wrote this to show the merit of passing references to structure fields (but may not be good model for this) This is useful for model like Node.Children(3).Parent(). Whether pass the reference or not is depend on design.
16

In many cases this is preferable

func (s Store) GetCar() *Car

because it is more convenient and readable, but has consequences. All variables such as Car are created inside the function which means they are placed onto stack. After function return this memory of stack is marked as invalid and can be used again. It a bit differs for pointer values such as *Car. Because pointer is virtually means you want to share the value with other scope and return an address, the value has to be stored somewhere in order to be available for calling function. It is copied onto heap memory and stays there until garbage collection finds no references to it.

It implies overheads:

  • copying values from stack to heap
  • additional work for garbage collection

The overheads is not significant if the value is relatively small. This is a reason why we have to pass an argument in io.Reader and io.Writer rather than have the value in return.

If you'd like to dive yourself into guts follow the links: Language Mechanics On Stacks And Pointers and Bad Go: pointer returns

Comments

6

The most common way to do that would be to write it as:

func (s Store) GetCar() *Car

Or, if you don't want to use pointers, you can do it like:

func (s Store) GetCar() Car

The other alternative, making it GetCar(aCar *Car) might work, but it will not be as clear since it's not obvious that aCar should be sent empty and then populated by the function.

2 Comments

In case I don't return a pointer, wouldn't I have a duplicated space in memory since im returning a clone of the already stored in memory object ?
You'd be allocating memory two times in that case, yes. But right after you return, the object created inside the function will be de-allocated since it was just a local variable. This should not be a problem for typical cases, but might affect performance if you are allocating really huge objects.
-1

Create them on heap from beginning by new.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.