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}
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
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