hakeの日記

Windows環境でプログラミングの勉強をしています。

Go言語 - インターフェース

インターフェースの使用方法の勉強。
いまひとつ理解できていないような気がしますが……
あるインターフェース型で宣言した変数や関数の仮引数は、そのインターフェース型で定義したメソッドを持つデータ型のみ代入可能ということで良いのかな?
あるインターフェース型を仮引数にした場合、その仮引数は確実に定義したメソッドが使えるということが保障される。

反対に考えると、メソッドを何も定義していないインターフェース型は、どんなデータ型でも受け取ることができるということ。

package main

import "fmt"

type StS struct{              // stringを返すGetメソッドを持つ構造体
	v string
}
func (t *StS) Get() string {
	return t.v
}

type StI struct{              // intを返すGetメソッドを持つ構造体
	v int
}
func (t *StI) Get() int {
	return t.v
}

type StN struct{}             // メソッドを持たない構造体



type mystring string         // stringを返すGetメソッドを持つ他の型を定義
func (t mystring) Get() string {
	return string(t)
}




type GetterS interface {     //  インターフェースとして
	Get() string         //    stringを返すGetメソッドを定義
}
func PrintS(i GetterS){      //  GetterS型を引数に持つ関数
	fmt.Println(i.Get())
}



type AllOK interface{}       // メソッドを持たないインターフェース型
func PrintA(i AllOK){        // AllOK型を引数に持つ関数
	fmt.Println(i)
}



func main() {

	// interface GetterS型の変数の宣言
	var a, e    GetterS
//	var b, c, d GetterS

	var x mystring = "baz"


	// interface GetterS型の変数には、pointer receiverを持ち、
	//   stringを返すGetメソッドを持つ型のみ代入可能

	a = &StS{"foo"} // ok

//	b = StS{"bar"}  // レシーバがポインタで無いのでエラー
                    // cannot use StS literal (type StS) as type GetterS in assignment:
                    // StS does not implement GetterS (Get method has pointer receiver)

//	c = StI{10}     // 戻り値の型が違うのでエラー
                    // cannot use StI literal (type StI) as type GetterS in assignment:
                    // StI does not implement GetterS (wrong type for Get method)
                    // have Get() int
                    // want Get() string

//	d = StN{}       // Getメソッドが無いのでエラー
                    // cannot use StN literal (type StN) as type GetterS in assignment:
                    // StN does not implement GetterS (missing Get method)

        e = x           // ok


	fmt.Println(a.Get()) // -> foo
	fmt.Println(e.Get()) // -> baz

	// GetterS型インターフェースを引数に持つ関数
	PrintS(a)    // -> foo
	PrintS(e)    // -> baz






	// AllOK型インターフェースを引数に持つ関数
	PrintA(&StS{"foo"}) // -> &{foo}
	PrintA(StS{"bar"})  // -> {bar}
	PrintA(StI{10})     // -> {10}
	PrintA(StN{})       // -> {}
	PrintA(x)           // -> baz

}