インターフェース

インターフェース #

特定のメソッドを実装した型を抽象型として扱う #

package main

type S1 struct{}

func (s *S1) String() string {
	return "S1.String"
}

type S2 struct{}

type S3 struct{}

func (s *S3) String(in string) string {
	return "S2.String"
}

type I interface {
	String() string
}

func main() {
	s1 := new(S1)
	s2 := new(S2)
	s3 := new(S3)

	var i I

	// S1 は String メソッドを実装しているので I 型の変数 i に代入できる
	i = s1

	// S2 は String メソッドを実装していないので I 型の変数 i に代入しようとすると panic になる
	i = s2
	/*
		./prog.go:32:4: cannot use s2 (type *S2) as type I in assignment:
			*S2 does not implement I (missing String method)
	*/

	// S3 は String メソッドを実装しているが引数の型が異なるため I の型の変数 i に代入しようとすると panic になる
	i = s3
	/*
		./prog.go:39:4: cannot use s3 (type *S3) as type I in assignment:
			*S3 does not implement I (wrong type for String method)
				have String(string) string
				want String() string
	*/

}
play_circleRun open_in_newRun In The Playground

抽象型から具象型への変換をする #

package main

import "fmt"

type S1 struct{}

func (s *S1) String() string {
	return "S1.String"
}

type S2 struct{}

func (s *S2) String() string {
	return "S2.String"
}

type I interface {
	String() string
}

func main() {
	s1 := new(S1)
	s2 := new(S2)

	var i1 I = s1
	var i2 I = s2

	// タイプアサーションで具象型へ変換
	s1_2, ok := i1.(*S1)
	fmt.Printf("%#v, %v\n", s1_2, ok) // == &main.S1{}, true

	// 変換できない場合は false が返る
	s2_2, ok := i1.(*S2)
	fmt.Printf("%#v, %v\n", s2_2, ok) // == &main.S1{}, true

	// switch で具象型へ変換
	switch v := i2.(type) {
	case *S2:
		fmt.Printf("%#v\n", v) // == &main.S1{}, true
	}
}
play_circleRun open_in_newRun In The Playground

要求実装のない空の抽象型をAny型として扱う #

interface に実装するべきメソッドを定義しない場合、どんな型の値も入れられるようになり、他言語でいう Any 型のようにあつかえる。

package main

import "fmt"

func main() {
	// 空の interface を作成
	var i interface{}

	// 任意の値を代入できる
	i = 1
	i = 1.1
	i = "hello"
	i = struct{}{}
	i = true

	fmt.Printf("%#v\n", i) // == true

	v, ok := i.(bool)
	fmt.Printf("%v, %v\n", v, ok) // == true
}
play_circleRun open_in_newRun In The Playground