Go のインターフェース

Go のインターフェースと型アサーション

インターフェース

インターフェースは Go で多態性を実現する。異なる型が同じメソッドを実装していれば、共通の API を通じて扱える。

次のインターフェースは ToString() メソッドを要求する。PersonBook はこのメソッドを実装しているため、自動的に条件を満たす。

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: "Go を学ぼう。"})
}

interface{} 型

interface{} は任意の型の値を受け取れる。Go 1.18 以降では、その別名である any も使用できる。

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

特定の型として値を取得するには、型アサーションを使用する。

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

型アサーションでは、変換に成功したかを表す真偽値も受け取れる。

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

型 switch を使うと、型ごとに処理を分けられる。

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

interface{} を使うと、入れ子になったマップも表現できる。

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

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