DEV Community

Cover image for Go Interfaces Explained: How to Write Flexible, Testable Go Code
Kenta Takeuchi
Kenta Takeuchi

Posted on • Originally published at bmf-tech.com

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

#go

This article was originally published on bmf-tech.com.

Overview

Summarizing Golang interfaces.

What is a Golang Interface

  • A type that enumerates only specific method types.
  • A struct that implements all methods declared in the interface Foo can be treated as type Foo.
  • Using interfaces allows for the realization of polymorphism.

Definition of an Interface

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

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...
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

Type Assertion

The syntax for type assertion.

<variable>.(<type>)
Enter fullscreen mode Exit fullscreen mode

It is used in a way that takes two variables.

s, ok := i.(Human)
Enter fullscreen mode Exit fullscreen mode

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}
}
Enter fullscreen mode Exit fullscreen mode

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)
  }
}
Enter fullscreen mode Exit fullscreen mode

References

Top comments (0)