In the world of Go programming, managing the initialization of structs is a common task. Structures in Go can often be initialized using their zero values. However, there are scenarios where these zero values do not represent meaningful defaults, or when initialization requires specific parameters.
In my post, func init(){}, I'm making some parallels with OOP constructors when describing the init
function in Go. However that feature do not work that great with generic initialization of data structures. Lets look how this is done in Go.
As an example we will use this Person
struct.
type Person struct {
firstName
lastName
}
Initializing a struct within the same package is straightforward, as illustrated by the following example:
person := Person{
firstName: "John",
lastName: "Doe",
}
However, this approach encounters issues when used in a different package due to the private nature of the fields. Restricting access to struct fields by making them private is a common practice. This encapsulation helps enforce certain conditions, or invariants, when initializing the data structure. For instance, you might want to ensure that the firstName
field is never an empty string, or there may be other properties on the struct that require specific conditions to be met for proper initialization.
The solution to this is to create an initialization function. These functions are usually named, New<struct name>
, so in this case we would call the function, NewPerson
.
func NewPerson(firstName, lastName string) *Person {
return &Person{
firstName: firstName,
lastName: lastName,
}
}
or if we want to enforce a certain condition.
func NewPerson(firstName, lastName string) (*Person, error) {
if firstName == "" {
return nil, fmt.Errorf("firstName cannot be empty")
}
return &Person{
firstName: firstName,
lastName: lastName,
}, nil
}
A common pattern is to define a constructor function that returns a pointer to a new instance of the struct as the example above.
However it's is also possible to return the new struct as a value instead.
func MakePerson(firstName, lastName string) Person {
return Person{
firstName: firstName,
lastName: lastName,
}
}
It's not that uncommon to name the function with the prefix, Make
, instead of, New
, to indicate that it doesn't return a struct pointer.
That's it, naming convention, keep it simple and straightforward seems to be the recipe of Go.
You can read more about constructors and composite literals in the Go documentation, Effective Go.
Happy hacking!