読者です 読者をやめる 読者になる 読者になる

覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。 twitter: @yyoshikaw

Go言語 - interfaceを触ってみる

Go言語にはメソッドの型だけを定義したinterfaceというものが存在しています。
interfaceは型の一種であり、任意の型が"どのようなメソッドを実装するべきか"を規定するためのものです。

大雑把にいえばJavaでいうところのinterfaceに似たものです。
interfaceを利用することで、オブジェクト指向言語でいうところのポリモーフィズムと同様の機能を実現できます。


インターフェースの定義は以下のように記述します(メソッドは複数記述することができます)

type <型名> interface {
    <メソッド名>(<引数の型>, ...) (<戻り値の型>, ...)
    ・
    ・
}


■具体的なインターフェスの定義

本エントリ内の各サンプルプログラムで利用するためのインターフェスとして、
describeというものを以下のように定義しました。説明文をstring型で返すdescriptionメソッドを1つだけ持ちます

type describe interface {
    description() string
}


■インターフェスを引数に取る関数

describeインターフェースを利用するprintDescription関数を定義して以降のサンプルで利用します。
printDescription関数は、descriptionメソッドを実行して説明文を取得し、その説明文を標準出力に書きだすだけのものです)

func printDescription(d describe) {
    fmt.Printf("Description: %s\n", d.description())
}


以下の各サンプルで具体的にdescribeインターフェースを実装してみます。


既存の組み込み型にインターフェースを実装させる

正確には既存の組み込み型には追加で新しいインターフェースを実装させることはできませんが、
typeを使って既存の組み込み型の別名の型を定義することで、その新しい型にインターフェースを実装させることができます。
本サンプルではint型の別名の方に実装させます


■インターフェースを実装

type MyInt int

// 組み込み型の別名の型をレシーバにして対象インターフェースのメソッドを定義
func (i MyInt) description() string {
    return fmt.Sprintf("MyInt is actually int. value is %d", i)
}


■実行サンプル

func main() {
    val1 := MyInt(100)
    printDescription(val1)
}

■実行結果

Description: MyInt is actually int. value is 100


構造体にインターフェースを実装させる

構造体もtypeで別名を付けて定義することでインターフェースを実装させることができます


■インターフェースを実装

type Square struct {
    edgeLength int
}

// 構造体をレシーバにして対象インターフェースのメソッドを定義
func (sq *Square) description() string {
    return fmt.Sprintf("The lengths of all four sides are equal. [edgeLength: %d]", sq.edgeLength)
}


■実行サンプル

func main() {
    sq := &Square{edgeLength: 10}
    printDescription(sq)
}

■実行結果

Description: The lengths of all four sides are equal. [edgeLength: 10]


関数にインターフェースを実装させる

関数もtypeで別名を付けて定義することでインターフェースを実装させることができます


■インターフェースを実装

type Product struct {
    id    uint
    name  string
    price uint
    PR    PRStatement
}

type PRStatement func() string

// PRStatementという関数をレシーバにして対象インターフェースのメソッドを定義
func (pr PRStatement) description() string {
    return pr()
}


■実行サンプル

func main() {
    p1 := &Product{id: 1, name: "Golang PC", price: 10000}
    p1.PR = func() string {
        return fmt.Sprintf("この %s は、値段が%d円なのでとてもお買い得です", p1.name, p1.price)
    }
    printDescription(p1.PR)

    p2 := &Product{id: 2, name: "リンゴ", price: 100}
    p2.PR = func() string {
        return fmt.Sprintf("この %s は、とても美味しいです", p2.name)
    }
    printDescription(p2.PR)
}

■実行結果

Description: この Golang PC は、値段が10000円なのでとてもお買い得です
Description: この リンゴ は、とても美味しいです

describeインターフェースの実装内容によって出力結果が変わっています。


まとめ

というわけでinterfaceを利用することで、Goのプログラムに型の柔軟性を与えることができることが分かりました



関連エントリ