Golang Working with interface

Golang Working with interface

Note: To execute golang code online you can use https://play.golang.org/

What is an interface?

  • An interface is defined as a custom datatype which contains set of unimplemented methods.
  • The interface defines the behavior for similar type of objects.
  • Go Interfaces are implemented implicitly
  • To implement an interface, you just need to implement all the methods declared in the interface.

syntax to create an interface

type InterfaceName interface {
    Method1() float64
    Method2() int
}

woking with interface

Let's see a simple example to find the area and perimeter of a shape.

package main

import (
    "fmt"
    "reflect"
    "math"
)

type Shape interface {
    GetArea() float64;
    GetPerimeter() float64;
}

type Circle struct {
    Radius float64
}

func(c Circle) GetArea() float64 {
    return math.Pi * math.Pow(c.Radius, 2)
}

func(c Circle) GetPerimeter() float64 {
    return 2 * math.Pi * c.Radius
}

type Rectangle struct {
    Length float64
    Width float64
}

func(r Rectangle) GetArea() float64 {
    return r.Length * r.Width
}

func(r Rectangle) GetPerimeter() float64 {
    return 2 * (r.Length + r.Width)
}

func GetTotalArea(shapes ...Shape) float64{
    sum := 0.0;
    for _, obj:= range shapes{
        sum = sum + obj.GetArea()
    }
    return sum
}

func main() {
    var s Shape = Circle{Radius: 3}
    fmt.Printf("Type: %s , Area: %f\n", reflect.TypeOf(s), s.GetArea())

    s = Rectangle{Length: 10, Width: 20}
    fmt.Printf("Type: %s , Area: %f\n", reflect.TypeOf(s), s.GetArea())

    // find total area 
    totalArea := GetTotalArea(Circle{Radius: 3}, Rectangle{Length: 10, Width: 20})
    fmt.Println("total area = ", totalArea)
}
- In the above code, we have two objects types which are Rectangle and Circle and an interface Shape. - We also have a function GetTotalArea which takes an array of objects of type interface and iterates through each and finds the total area. - To the function GetTotalArea we can pass any object which has methods GetArea and GetPerimeter. - As we can see, we have written a generic function to calculate the total area irrespective of the object data type. It will be a complex if we didn't use an interface. - We use interfaces when we have a dynamic assignment of data objects which has the similar behaviour as the interface.

using interface with switch statement

package main
import "fmt"


func PrintInterfaceType(x interface{}) {
    switch x.(type) {
    case bool:
        fmt.Print(x.(bool))
    case int:
        fmt.Print(x.(int))
    case float64:
        fmt.Print(x.(float64))
    case complex128:
        fmt.Print(x.(complex128))
    case string:
        fmt.Print("string: ", x.(string))
    case chan int:
        fmt.Print(x.(chan int))
    default:
        fmt.Print("Unknown type")
    }
    fmt.Print("\n")
}

func main(){
    var name interface{} = "Hello";
    PrintInterfaceType(name)
    // output: string: Hello
}
- We can use .(type) to find the data type of the interface object. - We have a limitation for .(type) syntax, we can only use it inside of a switch case. - We have implemented the similar behaviour with switch statement.

finding type of data passed to interface

  • In the above example we have seen how to get an actual type of interface object.
  • But, we do have a similar package in golang which provides the similar functionality.
  • By using package reflect, we can perform similar functionality easily.
  • Let's an example
package main

import "fmt"
import "reflect"

func main() {
    var x interface{}
    x = 3.14

    t := reflect.TypeOf(x)
    v := reflect.ValueOf(x) // x.(<type>)

    fmt.Printf("x: type = %v, value = %v\n", t, v)
    goo := x
    fmt.Printf("goo: type = %T, value = %v\n", goo, goo)

    x = &struct{ name string }{}

    t = reflect.TypeOf(x)
    v = reflect.ValueOf(x) // x.(<type>)
    fmt.Printf("x: type = %v, value = %v\n", t, v)
    hoo := x
    fmt.Printf("hoo: type = %T, value = %v\n", hoo, hoo)
}

The above will produce the output something like below

x: type = float64, value = 3.14
goo: type = float64, value = 3.14
x: type = *struct { name string }, value = &{}
hoo: type = *struct { name string }, value = &{}

References:

  1. https://golang.org/pkg/reflect/