Constructors in Go

There are some equivalents of constructors for when the zero values can't make sensible default values or for when some parameter is necessary for the struct initialization.

Supposing you have a struct like this :

type Thing struct {
    Name  string
    Num   int
}

then, if the zero values aren't fitting, you would typically construct an instance with a NewThing function returning a pointer :

func NewThing(someParameter string) *Thing {
    p := new(Thing)
    p.Name = someParameter
    p.Num = 33 // <- a very sensible default value
    return p
}

When your struct is simple enough, you can use this condensed construct :

func NewThing(someParameter string) *Thing {
    return &Thing{someParameter, 33}
}

If you don't want to return a pointer, then a practice is to call the function makeThing instead of NewThing :

func makeThing(name string) Thing {
    return Thing{name, 33}
}

Reference : Allocation with new in Effective Go.


There are actually two accepted best practices:

  1. Make the zero value of your struct a sensible default. (While this looks strange to most people coming from "traditional" oop it often works and is really convenient).
  2. Provide a function func New() YourTyp or if you have several such types in your package functions func NewYourType1() YourType1 and so on.

Document if a zero value of your type is usable or not (in which case it has to be set up by one of the New... functions. (For the "traditionalist" oops: Someone who does not read the documentation won't be able to use your types properly, even if he cannot create objects in undefined states.)


Go has objects. Objects can have constructors (although not automatic constructors). And finally, Go is an OOP language (data types have methods attached, but admittedly there are endless definitions of what OOP is.)

Nevertheless, the accepted best practice is to write zero or more constructors for your types.

As @dystroy posted his answer before I finished this answer, let me just add an alternative version of his example constructor, which I would probably write instead as:

func NewThing(someParameter string) *Thing {
    return &Thing{someParameter, 33} // <- 33: a very sensible default value
}

The reason I want to show you this version is that pretty often "inline" literals can be used instead of a "constructor" call.

a := NewThing("foo")
b := &Thing{"foo", 33}

Now *a == *b.


I like the explanation from this blog post:

The function New is a Go convention for packages that create a core type or different types for use by the application developer. Look at how New is defined and implemented in log.go, bufio.go and cypto.go:

log.go

// New creates a new Logger. The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) * Logger {
    return &Logger{out: out, prefix: prefix, flag: flag}
}

bufio.go

// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) * Reader {
    return NewReaderSize(rd, defaultBufSize)
}

crypto.go

// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
    if h > 0 && h < maxHash {
        f := hashes[h]
        if f != nil {
            return f()
        }
    }
    panic("crypto: requested hash function is unavailable")
}

Since each package acts as a namespace, every package can have their own version of New. In bufio.go multiple types can be created, so there is no standalone New function. Here you will find functions like NewReader and NewWriter.


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.

package main

import "fmt"

type Thing struct {
    Name string
    Num int
}

func (t *Thing) Init(name string, num int) {
    t.Name = name
    t.Num = num
}

func main() {
    t := new(Thing)
    t.Init("Hello", 5)
    fmt.Printf("%s: %d\n", t.Name, t.Num)
}

The result is:

Hello: 5