概要
Tour of Go の - Empty interfaces についてのサンプル。
今回は、空インタフェースについて。
Goには、interface{}
という型があります。空インターフェースといいます。
この型、他の言語でいう Object 型みたいなイメージです。
つまり、どんな型も interface{} になれる。
当然といえば、当然で interface{}
ということは定義されているメソッドが一つもないインターフェースってことです。
Goでは、対象のインターフェースを明示的に implements すると宣言しなくても、インターフェースに定義されているメソッドと同じシグネチャで定義していれば、そのインターフェースを実装していることになります。
なので、一つも定義を持たないインターフェースは、みんな何もしなくても実装出来ていることになります。
なので、interface{}
は、どの型からも変換可能となります。
サンプル
package tutorial import "fmt" type ( myIf interface { } myIfImpl struct { } data struct { value string } ) func (d *data) String() string { return fmt.Sprintf("[data] value:%v", d.value) } func (m *myIfImpl) String() string { return "myIfImpl" } // EmptyInterface は、 Tour of Go - The empty interface (https://tour.golang.org/methods/14) の サンプルです。 func EmptyInterface() error { // ------------------------------------------------------------ // 空のインターフェース // Go言語において、メソッドを一つも持たないインターフェースを interface{} で表す. // このインターフェースを空のインターフェースと呼ぶ。 // // Go言語では、この空のインターフェースは他の言語の Object 型に相当する. // つまり、 interface{} は任意の型の値を保持出来る. // ------------------------------------------------------------ var ( v interface{} ) v = 100 p(v) v = "helloworld" p(v) v = true p(v) v = &data{value: "data-value"} p(v) v = &myIfImpl{} p(v) var inf myIf = v p(inf) return nil } func p(v interface{}) { fmt.Printf("%v\n", v) }
try-golang/tutorial_gotour_20_empty_interface.go at master · devlights/try-golang · GitHub
実行すると以下な感じ。
[Name] "tutorial_gotour_empty_interface" 100 helloworld true [data] value:data-value myIfImpl myIfImpl
インターフェースの合成について
C#やJavaなどの言語では、インターフェースの継承という概念があります。そのままの意味ですが、とあるインターフェースはとあるインターフェースを継承しているという意味となります。
各インターフェースをfatにせずに、シンプルに定義して、特定の単位でそれをまとめるインターフェースとかはよく作ったりします。
Goには、継承という概念はありません。クラスという概念がないので当然ですが。では、複合インターフェースみたいなのは作れないのか?ってなりますが、そんなことはなく、合成インターフェースという形で作ります。
合成(Composition) という概念は、オブジェクト指向ではよく聞く言葉ですね。よく継承と対比されます。 ( Inheritance vs Composition)
インターフェースの合成は以下のようにします。
type ( // 普通のインターフェース1 if01 interface { f1() string } // 普通のインターフェース2 if02 interface { f2() string } // 合成インターフェース. if01とif02というインターフェースを合成している. // このインターフェースをするには if01とif02のインターフェース定義を満たす必要がある ifComposition interface { if01 if02 } )
そのまんまです。合成したいインターフェースを並べます。
以下、ちょっとしたサンプルです。
package interface_ import "fmt" type ( // 普通のインターフェース1 if01 interface { f1() string } // 普通のインターフェース2 if02 interface { f2() string } // 合成インターフェース. if01とif02というインターフェースを合成している. // このインターフェースをするには if01とif02のインターフェース定義を満たす必要がある ifComposition interface { if01 if02 } // 実装 compositionImpl struct{} ) // impl: if01.f1 func (c *compositionImpl) f1() string { return "hello" } // impl: if02.f2 func (c *compositionImpl) f2() string { return "world" } // Composition は、 Goのインターフェースのコンポジション (合成) についてのサンプルです. func Composition() error { // ---------------------------------------------------------------- // インターフェースのコンポジションについて // // Goでは、インターフェースを合成する場合、合成インターフェースを定義して // 属性に各インターフェースを列挙していく. // // io.ReadCloser, io.ReadWriter などが合成インターフェースの代表例 // ---------------------------------------------------------------- var ( c = &compositionImpl{} f1 = func(i if01) { fmt.Println(i.f1()) } f2 = func(i if02) { fmt.Println(i.f2()) } f3 = func(i ifComposition) { fmt.Println(i.f1(), i.f2()) } ) // 具象型からインターフェースへ var v ifComposition = c // 合成インターフェースは、合成元となっている各インターフェースを名乗ることが出来る f1(v) f2(v) f3(v) return nil }
実行すると以下のようになります。
[Name] "interface_composition" hello world hello world
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場