Structs Instead of Classes

Structs Instead of Classes

In this tutorial, we are going to discuss on how to use structs instead of classes in Go language. Go language is not a pure object oriented programming language.

Structs Instead of Classes

Go language does not provide classes but it does provide structsMethods can be added on structs. This provides the behavior of bundling the data and methods that operate on the data together similar to a class.

Let’s start with an example right away for a better understanding. We will create a custom package in this example as it helps to understand better how structs can be an effective replacement for classes.

Example

Create a subfolder inside ~/Documents/ and name it oop. Let’s initialize a go module named oop. Type the following command inside the oop directory to create a go mod named oop.

$ mkdir oop
$ cd oop
$ go mod init oop 

After running the above command, go will create a file called go.mod and the contents of this file is

module oop

go 1.15

Now create a subfolder employee inside oop. Inside the employee folder, create a file named employee.go. The folder structure would look like this,

├── Documents
│   └── oop
│       ├── employee
│       │   └── employee.go
│       └── go.mod

Now replace the contents of the employee.go with the following Go code.

package employee

import "fmt"

type Employee struct {
    FirstName   string
    LastName    string
    TotalLeaves int
    LeavesTaken int
}

func (e Employee) LeavesRemaining() {
    fmt.Printf("%s %s has %d leaves remaining\n", e.FirstName, e.LastName, (e.TotalLeaves - e.LeavesTaken))
}

In the above program, line no. 1 specifies that this file belongs to the employee package. An Employee struct is declared in line no. 5.

A method named LeavesRemaining is added to the Employee struct in line no. 12. This method calculates and displays the number of remaining leaves an employee has.

Now we have a struct and a method that operates on a struct bundled together similar to a class. So finally, create a file named main.go inside the oop folder. Now the folder structure would look like this,

├── Documents
│   └── oop
│       ├── employee
│       │   └── employee.go
│       ├── go.mod
│       └── main.go

Now replace the contents of main.go with the following Go code

package main

import "oop/employee"

func main() {
    emp := employee.Employee{
        FirstName:   "Ashok Kumar",
        LastName:    "Mariyala",
        TotalLeaves: 18,
        LeavesTaken: 2,
    }
    emp.LeavesRemaining()
}

Output

$ go run main.go 
Ashok Kumar Mariyala has 16 leaves remaining

In the above program, we imported the employee package in line no. 3 and we initialized Employee structure in line no.6. The LeavesRemaining() method of the Employee struct is called from line no. 12 in main().

This program cannot be run on the playground as it has a custom package if you run this program in your local by issuing the above command (go run main.go).

New() function instead of constructors

The program we wrote above looks alright, but there is a subtle issue in it.

Let’s see what happens when we define the employee struct with zero values. Replace the contents of main.go with the following code,

package main

import "oop/employee"

func main() {  
    var e employee.Employee
    e.LeavesRemaining()
}

The only change we have made is creating a zero value Employee in line no. 6 (Not initialized structure). This program will output,

  has 0 leaves remaining

As you can see, the variable created with the zero value of Employee is unusable. It doesn’t have a valid first name, last name, or valid leave details.

In other OOP languages like java, we can solve this problem by using constructors. A valid object can be created by using a parameterized constructor.

Go language doesn’t support constructors. Suppose the zero value of a type is not usable. In that case, it is the programmer’s job to unexport the type to prevent access from other packages and provide a function named NewT(parameters), which initializes the type T with the required values.

In Go, it is a convention to name a function that creates a value of type T to NewT(parameters). This will act as a constructor.

If the package defines only one type, then it’s a convention in Go to name this function just New(parameters) instead of NewT(parameters).

Let’s make changes to the program we wrote so that it is usable every time an employee is created.

Example
package employee

import (
    "fmt"
)

type employee struct {
    firstName   string
    lastName    string
    totalLeaves int
    leavesTaken int
}

func New(firstName string, lastName string, totalLeave int, leavesTaken int) employee {
    e := employee{firstName, lastName, totalLeave, leavesTaken}
    return e
}

func (e employee) LeavesRemaining() {
    fmt.Printf("%s %s has %d leaves remaining\n", e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken))
}

We have made some significant changes here. We have successfully unexported the employee struct and prevented access from other packages by doing lower case letters.

It’s a good practice to make all fields of an unexported struct to be unexported unless there is a specific need to export them.

Since we don’t need to access the fields of the employee struct anywhere outside the employee package, we have unexported all the fields too.

Now, since the employee is unexported, it’s impossible to create types Employee values from other packages.

Hence, we provide an exported New function that takes the required parameters as input and returns a newly created employee.

Now replace the contents of main.go with the following,

package main  

import "oop/employee"

func main() {  
    e := employee.New("Ashok Kumar", "Mariyala", 18, 2)
    e.LeavesRemaining()
}

Output

$ go run main.go 
Ashok Kumar Mariyala has 16 leaves remaining

Thus you can understand that although Go doesn’t support classes, structs can effectively be used instead of classes and methods of signature New(parameters) can be used in place of constructors.

That’s all about the Structs Instead of Classes in Go language. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Go language.!!

Structs Instead of Classes
Scroll to top