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のプログラムに型の柔軟性を与えることができることが分かりました