Interfaces in Go

Interfaces in Go

In this tutorial, we are going to discuss about interfaces in Go language. Go language interfaces are different from other languages.

In Go language, the interface is a custom type that is used to specify a set of one or more method signatures and the interface is abstract, so you are not allowed to create an instance of the interface.

But you are allowed to create a variable of an interface type and this variable can be assigned with a concrete type value that has the methods the interface requires.

In other words, the interface is a collection of methods as well as it is a custom type.

An interface in Go is a type defined using a set of method signatures. The interface defines the behavior for similar type of objects.

For example WashingMachine can be an interface with method signatures Cleaning() and Drying(). Any type which provides definition for Cleaning() and Drying() methods is said to implement the WashingMachine interface.

An interface is declared using the type keyword, followed by the name of the interface and the keyword interface. Then, we specify a set of method signatures inside curly braces.

type myinterface interface{ 
  fun1() int 
  fun2() float64 
}
Implementing an interface in Go

In Go language, to implement an interface, you just need to implement all the methods declared in the interface.

Unlike other languages like Java, you don’t need to explicitly specify that a type implements an interface using something like an implements keyword.

You just implement all the methods declared in the interface and you’re done.

type Shape interface { 
   Area() float64 
   Perimeter() float64 
}

Here are two Struct types that implement the above Shape interface

// Struct type Rectangle - implements the Shape interface by implementing all its methods.
type Rectangle struct {
    Length, Width float64
}
func (r Rectangle) Area() float64 {
    return r.Length * r.Width
}
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Length + r.Width)
}
// Struct type Circle - implements the Shape interface by implementing all its methods.
type Circle struct {
    Radius float64
}
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}
func (c Circle) Diameter() float64 {
    return 2 * c.Radius
}
Using an interface type with concrete values

An interface in itself is not that useful unless we use it with a concrete type that implements all its methods. Let’s see how an interface can be used with concrete values.

package main

import (
    "fmt"
    "math"
)

func main() {
    var s Shape = Circle{10.0}
    fmt.Printf("Shape Type = %T, Shape Value = %v\n", s, s)
    fmt.Printf("Area = %f, Perimeter = %f\n\n", s.Area(), s.Perimeter())

    s = Rectangle{5.0, 6.0} 
    fmt.Printf("Shape Type = %T, Shape Value = %v\n", s, s)
    fmt.Printf("Area = %f, Perimeter = %f\n", s.Area(), s.Perimeter())
 }

Output

Shape Type = main.Circle, Shape Value = {10} 
Area = 314.159265, Perimeter = 62.831853 
Shape Type = main.Rectangle, Shape Value = {5 6} 
Area = 30.000000, Perimeter = 22.000000
Using Interface types as arguments to functions
package main

import (
    "fmt"
)

// Generic function to calculate the total area of multiple shapes of different types
func CalculateTotalArea(shapes …Shape) float64 {
    totalArea := 0.0
    for _, s := range shapes {
        totalArea += s.Area()
    }
    return totalArea
}

func main() {
    totalArea := CalculateTotalArea(Circle{2}, Rectangle{4, 5}, Circle{10})
    fmt.Println("Total area = ", totalArea)
}

Output

Total area =  346.7256359733385
Empty interface

An interface that has zero methods is called an empty interface. It is represented as interface{}. Since the empty interface has zero methods, all types implement the empty interface.

package main

import "fmt"

func describe(i interface{}) {
   fmt.Printf("Type = %T, value = %v\n", i, i)
}

func main() {
   name := "Ashok Kumar"
   describe(name)
   
   age := 29 
   describe(age) 

   strt := struct {
     salary int 
   }{
     salary: 50000, 
   } 
   describe(strt)
}

Output

Type = string, value = Ashok Kumar 
Type = int, value = 29 
Type = struct { salary int }, value = {50000} 

Run in playground

Type assertion

Type assertion is used to extract the underlying value of the interface. i.(T) is the syntax which is used to get the underlying value of interface i whose concrete type is T.

A program is worth a thousand words πŸ˜€. Let’s write one for type assertion.

package main

import (
    "fmt"
)

func assert(i interface{}) {
    s := i.(string) //get the underlying int value from i
    fmt.Println(s)
}

func main() {
    var name interface{} = "Ashok Kumar"
    assert(name)
}

Output

Ashok Kumar

Run in playground

What will happen if the concrete type in the above program is not string? Well, let’s find out.

package main

import (
    "fmt"
)

func assert(i interface{}) {
    s := i.(string)
    fmt.Println(s)
}

func main() {
    var age interface{} = 29
    assert(age)
}

Output

panic: interface conversion: interface {} is int, not string

Interfaces in Go


Scroll to top