Go Doesn't Have Constructors, Just a Naming Convention
Go has no constructor keyword or new syntax, so the language leans on a plain function that returns a pointer, named NewX by convention.
Coming from languages with classes, one of the first things I noticed in Go is that there’s no constructor keyword and no new Class() syntax. Instead the language leans on a naming convention: a plain function that builds and returns a struct.
Constructors Are Just Functions That Return a Pointer
Start with the struct itself, since the constructor only makes sense in context of what it’s building:
type User struct { Name string Email string Age int}By convention, if the struct is User, the constructor is NewUser. Here’s the simplest version:
func newUser(name, email string, age int) *User { return &User{ Name: name, Email: email, Age: age, }}It returns a pointer (*User), not a value, for two reasons. Returning *User skips copying the whole struct, and any method called on that pointer mutates the original instead of a copy. That matters most for stateful things like a repository or a database handle, where you almost always want to pass around the same instance rather than a copy of it.
Capitalize it to NewUser if other packages need to call it. Go’s export rule is just the first letter’s case.
Constructors Give You a Place to Enforce Invariants
You can always build a struct directly, user := User{Name: "Bob"}, without ever calling a function. What a constructor buys you is a single place to enforce rules before the struct exists. If a User needs a valid email and has to be over 18, the constructor is where that check lives:
func NewUser(name, email string, age int) (*User, error) { if age < 18 { return nil, errors.New("user must be at least 18") }
return &User{ Name: name, Email: email, Age: age, }, nil}They Also Hide Setup the Caller Shouldn’t Have to Think About
Some structs need more than field assignment: a database connection, a map that has to be initialized with make(map[string]int), maybe a goroutine started in the background. A constructor is where that setup lives, so callers get a ready-to-use value instead of having to replicate the setup themselves.
Takeaway
Go’s constructors felt overly manual the first time I wrote one. Now I think that’s the point: there’s no hidden magic when you build a User, just a function returning a pointer. It’s more typing, but I always know exactly what happens when an object gets created.