Application 2018-11-15

Go Interfaces Explained: How to Write Flexible, Testable Go Code

A practical guide to Go interfaces. Learn implicit implementation, interface composition, using interfaces for dependency injection, and common design pitfalls.

Read in: ja
Go Interfaces Explained: How to Write Flexible, Testable Go Code

Overview

Summarizing Golang interfaces.

What is a Golang Interface

Definition of an Interface

type <TypeName> interface {
  <MethodName>(<ArgumentType>, ...)(<ReturnType>, ...)
}
// Ex.
type Human interface {
  say() string
}

Characteristics of Interfaces

Variables of Interface Type

Variables declared as interface type can hold values of any type.

var i interface{}

i = 123
i = "Hello World"
i = []int{1, 2, 3} // etc...

Interface Type Arguments

When an interface type is used as an argument, any type of value can be passed.

package main

import "fmt"

type Human struct {
  Name string
  Age int
}

func printType(i interface{}) {
  fmt.Printf("%T\n", i)
}

func main() {
  h := Human{
    Name: "John",
    Age: 20,
  }

  printType(h) // main.Human
}

Type Assertion

The syntax for type assertion.

<variable>.(<type>)

It is used in a way that takes two variables.

s, ok := i.(Human)

If variable i is of type Human, variable s will hold the actual value of variable i of type Human, and variable ok will be true. Conversely, if variable i is not of type Human, variable s will hold the zero value of type Human.

package main

import "fmt"

type Human struct {
  Name string
  Age int
}

type Alien struct {
  Name string
  Age int
}

func printOnlyHuman(i interface{}) {
  s, ok := i.(Human)

  if !ok {
    fmt.Printf("%v\n", "Not of type Human")
    fmt.Printf("%v\n", s)
    return
  }

  fmt.Printf("%v\n", "Is of type Human")
  fmt.Printf("%v\n", s)
}

func main() {
  h := Human{
    Name: "John",
    Age: 20,
  }

  a := Alien {
    Name: "Tom",
    Age: 200000,
  }

  printOnlyHuman(h) // Is of type Human. {John 20}
  printOnlyHuman(a) // Not of type Human. { 0}
}

Example of Interface Implementation

An example of a popular use case for Golang interfaces, which is to "add common properties to different types."

package main

import "fmt"

type Action interface {
  say()
}

type Human struct {}

type Alien struct {}

func (h *Human) say() {
  fmt.Println("I'm Human")
}

func (a *Alien) say() {
  fmt.Println("I'm Alien")
}

func do(a Action) { // Accepts Action type
  a.say()
}

func main() {
  ha := []Action{
    &Human{},
    &Alien{},
  }

  for _, v := range ha {
    do(v)
  }
}

References

Tags: Golang
Share: 𝕏 Post Facebook Hatena
✏️ View source / Discuss on GitHub
☕ Support

If you enjoy this blog, consider supporting it. Every bit helps keep it running!


Related Articles