Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should constructor of Go return address?

I understand that Go doesn't have any constructors and a New func is used in its place, but according to this example.

func NewFile(fd int, name string) *File {
  if fd < 0 {
    return nil
  }
  f := File{fd, name, nil, 0}
  return &f
}

They always return &f. Why just simply returning File isn't suffice?

Update

I've tried returning the created object for a simple struct and it's fine. So, I wonder if returning an address is a standard way of constructor or something.

Thanks.

like image 606
Bhoomtawath Plinsut Avatar asked Aug 11 '15 03:08

Bhoomtawath Plinsut


People also ask

Is there constructor in Golang?

There are no default constructors in Go, but you can declare methods for any type. You could make it a habit to declare a method called "Init". Not sure if how this relates to best practices, but it helps keep names short without loosing clarity.

What is new function in Golang?

New() Function in Golang is used to get the Value representing a pointer to a new zero value for the specified type. To access this function, one needs to imports the reflect package in the program. Syntax: func New(typ Type) Value.


1 Answers

As mentioned, yes, the spec allows you to return either values (as non-pointers) or pointers. It's just a decision you have to make.

When to return pointer?

Usually if the value you return is "more useful" as a pointer. When is it more useful?

For example if it has many methods with pointer receiver. Yes, you could store the return value in a variable and so it will be addressable and you can still call its methods that have pointer receivers. But if a pointer is returned right away, you can "chain" method calls. See this example:

type My int

func (m *My) Str() string { return strconv.Itoa(int(*m)) }

func createMy(i int) My { return My(i) }

Now writing:

fmt.Println(createMy(12).Str())

Will result in error: cannot call pointer method on createMy(12)

But if works if you return a pointer:

func createMy(i int) *My { return (*My)(&i) }

Also if you store the returned value in a data structure which is not addressable (map for example), you cannot call methods on values by indexing a map because values of a map are not addressable.

See this example: My.Str() has pointer receiver. So if you try to do this:

m := map[int]My{0: My(12)}
m[0].Str() // Error!

You can't because "cannot take the address of m[0]". But the following works:

m := map[int]*My{}
my := My(12)
m[0] = &my // Store a pointer in the map

m[0].Str() // You can call it, no need to take the address of m[0]
           // as it is already a pointer

And another example for pointers being useful is if it is a "big" struct which will be passed around a lot. http.Request is a shining example. It is big, it is usually passed around a lot to other handlers, and it has methods with pointer receiver.

If you return a pointer, that usually suggests that the returned value is better if stored and passed around as a pointer.

like image 51
icza Avatar answered Sep 18 '22 01:09

icza