Introduction to golang constructor
Go by design is not an Object Oriented Programming language (OOP) like Java and Python. This means that Go does not offer constructors natively like Java and Python does. The idiomatic way for setting up a new data structure using constructors is to use proper zero values coupled with factory function.
To construct a decimal degrees location from degrees, minutes, and seconds, you can use the decimal method with a composite literal:
type location struct {
lat, long float64
}
curiosity := location{lat.decimal(), long.decimal()}
If you need a composite literal that’s anything more than a list of values, consider writing a constructor function. The following listing declares a constructor function named newLocation
.
// newLocation from latitude, longitude d/m/s coordinates.
func newLocation(lat, long coordinate) location {
return location{lat.decimal(), long.decimal()}
}
Classical languages provide constructors as a special language feature to construct objects. Python has _init_
, Ruby has initialize
, and PHP has __construct()
. Go doesn’t have a language feature for constructors. Instead newLocation
is an ordinary function with a name that follows a convention.
In this article we will learn about Go constructors and how to code constructors the easy way. This article will focus on creating constructors :
- Using Composite Literal
- Using Init method
- NewXxx constructor
Different methods to create golang constructor
Method-1: Using Composite Literal
This is the most simple and direct way of initializing a type in Go. This method has its disadvantages though.
Example
package main
import "fmt"
type Movie struct {
title string
rating int
}
func (m *Movie) printTitle() {
fmt.Printf("Movie title is :%s\n", m.title)
}
func (m *Movie) printRating() {
fmt.Printf("Rating is :%d \n", m.rating)
}
func main() {
m := Movie{
title: "Top Gun",
rating: 5,
}
m.printTitle()
m.printRating()
}
Explanation
In the above example we define a Movie struct
with two fields. This Movie type has two receiver functions namely printTitle()
and printRating()
, that print the movie title
and movie rating
respectively. In the main function we define a new movie m
with initial values for title and rating. We have constructed a new movie struct using composite literals.
Output
$ go run main.go
Movie title is :Top Gun
Rating is :5
Method-2: Using Init method
We can initialize a type using a custom init()
method.
Example
package main
import "fmt"
type Movie struct {
title string
rating int
}
func (m *Movie) init(title string, rating int) {
m.title = title
m.rating = rating
}
func (m *Movie) printTitle() {
fmt.Printf("Movie title is :%s\n", m.title)
}
func (m *Movie) printRating() {
fmt.Printf("Rating is :%d \n", m.rating)
}
func main() {
m := new(Movie)
m.init("Free Guy", 5)
m.printTitle()
m.printRating()
}
Explanation
In the above example, we define a Movie struct
type with title
and rating
fields. We also define a receiver init() function that constructs a new movie type.The init() function takes the title and rating as arguments, which are used to construct a new movie type. The Movie struct also has two more receiver functions namely printTitle()
and printRating()
.
In the main function, we initialize a new Movie using the new()
function. The new()
function in Go constructs all data types in Go except channels and maps, with their respective zero values. It returns a pointer to the memory location of the new type. In the above example, we construct a new Movie
type with title
and rating
fields assigned values.
Output
$ go run main.go
Movie title is :Free Guy
Rating is :5
Method-3: NewXxx constructor
The naming convention for this function is to start with the New word then adding the name of the things you want to construct. For example, if you want to create a new Movie, the function name will be NewMovie().
This function is a factory function and it therefore creates a new type of a thing. For efficient memory usage, they can be defined to return a pointer.
Example
package main
import "fmt"
type Movie struct {
title string
rating int
}
func (m *Movie) printTitle() {
fmt.Printf("Movie title is :%s\n", m.title)
}
func (m *Movie) printRating() {
fmt.Printf("Rating is :%d \n", m.rating)
}
func NewMovie(title string, rating int) *Movie {
m := &Movie{
title: title,
rating: rating,
}
return m
}
func main() {
m := NewMovie("Top Gun Maverick", 5)
m.printTitle()
m.printRating()
}
Explanation
In the above example, We define a Movie struct
with title
and rating
fields. The Movie type has two receiver functions namely printTitle()
and printRating()
.We also define a factory function called NewMovie()
that takes in as argument the title and rating of a movie . This function constructs a new movie and returns a pointer to the caller. In the main function,we create a new movie with title and rating. The returned value (m)
also has access to the methods printTitle()
and printRating()
Output
$ go run main.go
Movie title is :Top Gun Maverick
Rating is :5
Returning a value and an error from a constructor
Go takes error handling seriously , and it has a dedicated package(errors)
for error handling. An error might occur while constructing a new type. In this section, we will learn how to return a type and an error.
package main
import (
"errors"
"fmt"
"log"
)
type Movie struct {
title string
rating int
}
func (m *Movie) printTitle() {
fmt.Printf("Movie title is :%s\n", m.title)
}
func (m *Movie) printRating() {
fmt.Printf("Rating is :%d \n", m.rating)
}
func NewMovie(title string, rating int) (*Movie, error) {
if rating > 5 {
return nil, errors.New("Rate above 5")
}
m := &Movie{
title: title,
rating: rating,
}
return m, nil
}
func main() {
m, err := NewMovie("Top Gun Maverick", 6)
if err != nil {
log.Println(err)
} else {
m.printTitle()
m.printRating()
}
}
Explanation
In the above example, we have added an error type as part of the return types in the NewMovie()
function. We check if the rating is above 5 and return movie and an error. If a rating above 5 is passed, then we will return nil for the movie and an error errors.New(“Rate above 5”)
to the caller.
$ go run main.go
2022/10/02 12:04:11 Rate above 5
Summary
In this article , we learn about Go constructors. Go does not come with constructors natively but provides ways to construct new types. Combining methods and structures provides much of what classical languages provide without introducing a new language feature. Constructor functions are ordinary functions. We learn how to construct a new type with composite literals, Using Init()
method and finally using the NewXxx()
function.
Further Reading