Interface in Golang ( Golang interfaces )

Earlier, we discussed the structs in Golang and how they can be used in Golang. Structs coupled with methods provide the functionality of classes in object-oriented languages to some extent. There is one more feature of interfaces that few languages have, and Golang also has interfaces though its implementation might differ from other languages like Java.

An interface in Golang is a set of method signatures only, and the type providing the implementation of those methods is said to be implementing the interface.

This post will look at below points –

Let’s look at each point one by one.

How to create an interface

Below is the syntax used to create or declare an interface.

type interface_name interface{

//method signatures
method1()
method2() string

}
declare an interface in golang

An interface will contain only the method signatures and not their implementations. The type will provide the implementation or, we can say, the definition of the methods.

How to implement an interface in golang

Let’s create an interface first, and then we can see how we can implement the methods of an interface.

// interface
type Shape interface {
	area() float64
	perimeter() float64
}

Now, a type implementing the above interface has to implement both methods. Many languages require us to say that a type explicitly satisfies or implements an interface.

But we don’t need to do that in Golang. If a type implements all the methods of an interface, then Golang automatically assumes that the type implements the interface.

So, let’s create a struct type “Circle” to implement the “Shape” interface.

// "Circle" type
type Circle struct {
	radius float64
}

// Method implementations
func (c Circle) area() float64 {
	pie := 3.14
	return (pie) * (c.radius) * (c.radius)
}

func (c Circle) perimeter() float64 {
	pie := 3.14
	return 2 * (pie) * (c.radius)
}

As the “Circle” type implements both methods of the “Shape” interface, so, Golang will automatically assume that “Circle” implements “Shape” without explicitly having to say it.

Multiple types implementing a single interface

Right now, only a single type has implemented the interface, but it is not restricted to only one. Any number of types can implement an interface which is illustrated below.

Let’s create one more type, “Rectangle“, which will implement the interface.

type Rectangle struct {
	length  float64
	breadth float64
}

func (r Rectangle) area() float64 {
	return r.length * r.breadth
}

func (r Rectangle) perimeter() float64 {
	return 2 * (r.length + r.breadth)
}

So, now we have two types implementing a single interface.

// "Shape" interface
type Shape interface {
	area() float64
	perimeter() float64
}

// "Circle" type
type Circle struct {
	radius float64
}

func (c Circle) area() float64 {
	pie := 3.14
	return (pie) * (c.radius) * (c.radius)
}

func (c Circle) perimeter() float64 {
	pie := 3.14
	return 2 * (pie) * (c.radius)
}

// "Rectangle" type
type Rectangle struct {
	length  float64
	breadth float64
}

func (r Rectangle) area() float64 {
	return r.length * r.breadth
}

func (r Rectangle) perimeter() float64 {
	return 2 * (r.length + r.breadth)
}
Benefits of using interfaces
  • Interfaces are used to achieve abstraction. They can be used to hide the information wherever necessary.
  • An interface can help in code maintenance. If a new type implements an interface, it won’t require any code or logic change in a program. Only the type has to provide its implementation of the methods. In this way, we can easily maintain the code.
  • Interfaces in golang can also be used to achieve loose coupling. We can replace a piece of code in a loosely coupled code without affecting the whole structure.
How to use interfaces in a program

Now, we have created an interface and also the types implementing it. Now, we will see how we can use the interface in a program.

We can create the variable or reference of the interface and point it to any type implementing it.

  • create the variable of an interface
var shape Shape;
  • Point the variable to the type object implementing the interface
shape = Circle{ 
                  radius: 2,
               }

// Or we can also do it this way

circle =  Circle{
		           radius: 2,
               }
shape = circle

We can use the variable to call interface methods, which will call the implementation provided by the type to which we are pointing the interface variable.

shape.area() // this will call "Circle" type method implementation

Let’s write the whole program.

package main

import "fmt"

// "Shape" interface
type Shape interface {
	area() float64
	perimeter() float64
}

// "Circle" type
type Circle struct {
	radius float64
}

func (c Circle) area() float64 {
	pie := 3.14
	return (pie) * (c.radius) * (c.radius)
}

func (c Circle) perimeter() float64 {
	pie := 3.14
	return 2 * (pie) * (c.radius)
}

// "Rectangle" type
type Rectangle struct {
	length  float64
	breadth float64
}

func (r Rectangle) area() float64 {
	return r.length * r.breadth
}

func (r Rectangle) perimeter() float64 {
	return 2 * (r.length + r.breadth)
}

func main() {
	var shape Shape // making a variable

	// pointing the variable to "Circle" type
	shape = Circle{
		radius: 2,
	}

	fmt.Println("Area of circle: ", shape.area())

	// re-pointing the variable to "Rectangle" type
	shape = Rectangle{
		length:  2,
		breadth: 3,
	}

	fmt.Println("Area of rectangle: ", shape.area())
}

Output –

Area of circle:  12.56
Area of rectangle:  6

So, this is how we can use an interface in our program.

What if a type implements all methods of an interface plus some methods of its own?

We will create a new method in the “Circle” type, which is not declared by the “Shape” interface.

// "Circle" type
type Circle struct {
	radius float64
}

func (c Circle) area() float64 {
	pie := 3.14
	return (pie) * (c.radius) * (c.radius)
}

func (c Circle) perimeter() float64 {
	pie := 3.14
	return 2 * (pie) * (c.radius)
}

func (c Circle) displayRadius() {
	fmt.Println("Radius of circle: ", c.radius)
}

Now, the displayRadius() method is not declared by the interface, which gives rise to a couple of questions –

  • Is the “Circle” type still considered to be implementing the “Shape” interface?
  • And, can we call the displayRadius() method using the interface’s variable or reference?

Let’s answer them one by one.

Is the “Circle” type still considered to be implementing the “Shape” interface?

Yes. Because the “Circle” type implements all methods of the “Shape” interface, which satisfies the requirements of implementing an interface. We can still use the interface’s variable to call the implementation provided by the “Circle” type.

package main

import "fmt"

// "Shape" interface
type Shape interface {
	area() float64
	perimeter() float64
}

// "Circle" type
type Circle struct {
	radius float64
}

func (c Circle) area() float64 {
	pie := 3.14
	return (pie) * (c.radius) * (c.radius)
}

func (c Circle) perimeter() float64 {
	pie := 3.14
	return 2 * (pie) * (c.radius)
}

func (c Circle) displayRadius() {
	fmt.Println("Radius of circle: ", c.radius)
}

func main() {
	var shape Shape // making a variable

	// pointing the variable to "Circle" type
	shape = Circle{
		radius: 2,
	}

	fmt.Println("Area of circle: ", shape.area())
}

Output –

Area of circle:  12.56
Can we call the displayRadius() method using the interface’s variable or reference?

No. Using the interface’s variable, we cannot call such methods not declared by the interface.

package main

import "fmt"

// "Shape" interface
type Shape interface {
	area() float64
	perimeter() float64
}

// "Circle" type
type Circle struct {
	radius float64
}

func (c Circle) area() float64 {
	pie := 3.14
	return (pie) * (c.radius) * (c.radius)
}

func (c Circle) perimeter() float64 {
	pie := 3.14
	return 2 * (pie) * (c.radius)
}

func (c Circle) displayRadius() {
	fmt.Println("Radius of circle: ", c.radius)
}

func main() {
	var shape Shape // making a variable

	// pointing the variable to "Circle" type
	shape = Circle{
		radius: 2,
	}

	fmt.Println("Area of circle: ", shape.displayRadius())
}

Output –

shape.displayRadius undefined (type Shape has no field or method displayRadius)

We hope that you liked the article. If you have any doubts or concerns, please feel free to write us in the comments or mail us at [email protected]

There are a few more topics in interfaces which we have covered in separate posts –

Liked the article? Share this on

Leave a Comment

Your email address will not be published.