Go Interfaces

Go interfaces and type assertions

Interfaces

Interfaces provide polymorphism in Go. If different types implement the same methods, an interface can handle them through a common API.

The following interface requires a ToString() method. Person and Book satisfy it automatically because they implement that method.

package main

import "fmt"

type Printable interface {
	ToString() string
}

func PrintOut(p Printable) {
	fmt.Println(p.ToString())
}

type Person struct { name string }
func (p Person) ToString() string { return p.name }

type Book struct { title string }
func (b Book) ToString() string { return b.title }

func main() {
	PrintOut(Person{name: "devkuma"})
	PrintOut(Book{title: "Let's study Go."})
}

The interface{} Type

interface{} can receive a value of any type. Since Go 1.18, you can also use its alias, any.

func funcA(a interface{}) {
    // ...
}

Use a type assertion to retrieve a specific type.

func funcA(a interface{}) {
    fmt.Printf("%d\n", a.(int))
}

A type assertion can return a second Boolean value indicating whether conversion succeeded.

func PrintOut(a interface{}) {
    q, ok := a.(Printable)
    if ok {
        fmt.Println(q.ToString())
    } else {
        fmt.Println("Not printable.")
    }
}

Use a type switch to process different types.

func funcA(a interface{}) {
    switch a.(type) {
    case bool:
        fmt.Printf("%t\n", a)
    case int:
        fmt.Printf("%d\n", a)
    case string:
        fmt.Printf("%s\n", a)
    }
}

An interface{} value can also store nested map data.

type any interface{}
type dict map[string]any

p1 := dict{
    "name": "devkuma",
    "address": dict{"tel": "012-3456-7890"},
}
tel := p1["address"].(dict)["tel"]