Constructor like functions in Go
Go doesn’t have any OOP like constructors but it suggests to use constructor-like functions for initializing types. In this post I’ll list some use cases of constructor functions. These are just some idiomatic uses of the constructor, not any language bound constraints. All the examples are taken from the Go built-in libraries.
Initialize types with non-zero default values
Declaring variables, or calling of new
, or using composite literal without any explicit value, or calling of make
- in all these cases we get a zero valued variable. But sometimes we want the variables to be initialized with some sensible non-zero values. This is the most common use case of constructors. We can find this type of usage in almost all the built-in packages. For example in encoding/json
package:
We can also use the constructor functions to do some non-trivial initialization. For example, in ring list, only way to create a ring list of n element is through the constructor function. Without the constructor function, we end up having a ring list with only one element.
Multiple constructors with different initial values
Often we may need to construct our types based on different initial contents. We can either use one constructor with multiple optional parameters or use multiple constructors with different parameters. For example, look at the following definitions from bytes
package:
Another example from the bufio
package:
Prevent users from directly modifying private types e.g. Encapsulation
We can declare a type as private and also return an interface type from the constructor function. This way users won’t be able to manipulate our type directly. Only way to work with the type is to use the interface methods. For example, following is a snippet from the package md5
. Only way to work with the type is to use the constructor function and use the hash.Hash32
interface methods for any operation.
Using an interface type as return type is crucial here, otherwise we can directly change any public fields of the struct, even though the type itself is private.
Here is another example from the errors
package:
where the predeclared type error
is defined as an interface:
Finally I’v seen people implementing Factory method patterns using constructors. I’m not listing it here since I’m not a big fan of this pattern. Too much abstraction freezes my brain :(