Goプログラミング-インタフェース


抽象オブジェクトと対話する方法

1.宣言

type DuctInterface interface {
  Fly()
  Walk(distance int) int
}
  • メソッドにはメソッド名が必要
  • パラメータと戻りが違っても同名の方法はない
  • インタフェースにメソッドを含まない実装
  • 使用例
    package main
    
    import "fmt"
    
    type Stringer interface {
      String()
    }
    
    type Student struct {
      Name string
      Age int
    }
    
    func (s Student) String() {
      fmt.Printf("안녕 내 이름은 %s이고 나이는 %d살이야!\n", s.Name, s.Age)
    }
    
    func main() {
      student := Student{"철수", 31}
      var stringer Stringer
      stringer = student
    
      stringer.String()
    }

    2.インタフェースを使用する理由


    タイプ拡張に柔軟に対応

    問題の状況

  • 動物農場に子犬しかいないと仮定
  • package main
    
    import "fmt"
    
    type Dog struct {
      Name string
    }
    
    func (d Dog) Sound() {
      fmt.Printf("[%s]: 멍멍\n", d.Name)
    }
    
    func MakeSound(dogs []Dog) {
      for _, d := range dogs {
        d.Sound()
      }
    }
    
    func main() {
      dogs := []Dog{}
      dogs = append(dogs, Dog{"멍멍이"}, Dog{"왈왈이"})
      MakeSound(dogs)
    }
  • いきなり猫が増えたので、新しいタイプ定義が必要
  • type Cat struct {
      Name string
    }
    
    func (c Cat) Sound() {
      fmt.Printf("[%s]: 야옹\n", c.Name)
    }
  • ただし既存のMakeSound関数はDogタイプのみをパラメータとして受け入れるためCatに対応できない
  • // Dog 타입 슬라이스만 받음..
    func MakeSound(dogs []Dog) {
      for _, d := range dogs {
        d.Sound()
      }
    }

    ソリューション


    上記の例のSoundのような汎用メソッドインタフェースを作成します.
    package main
    
    import "fmt"
    
    type Animal interface {
      Sound()
    }
    
    type Dog struct {
      Name string
    }
    
    func (d Dog) Sound() {
      fmt.Printf("[%s]: 멍멍\n", d.Name)
    }
    
    type Cat struct {
      Name string
    }
    
    func (c Cat) Sound() {
      fmt.Printf("[%s]: 야옹\n", c.Name)
    }
    
    func MakeSound(animals []Animal) {
      for _, a := range animals {
        a.Sound()
      }
    }
    
    func main() {
      animals := []Animal{}
      animals = append(animals, Dog{"멍멍이"}, Dog{"왈왈이"}, Cat{"야옹이"})
      MakeSound(animals)
    }

    3.インタフェース機能の詳細


    3.1インタフェースを含むインタフェース

    type A interface {
    	AA() (int, error)
    	CC() error
    }
    
    type B interface {
    	BB() (int, error)
    	CC() error
    }
    
    type C interface {
    	A
    	B
    }
  • CC() error重なっていますが、同じ方法であるため問題ありません
  • 3.2パラメータとしてインタフェース{}を受信する空のインタフェース


    任意の値を許容できる関数、メソッド、変数値の作成
    package main
    
    import (
    	"fmt"
    )
    
    func TypeChecker(v interface{}) {
    
    	switch t := v.(type) {
    	case int:
    		fmt.Printf("v is int %d\n", v)
    	case string:
    		fmt.Printf("v is string %s\n", v)
    	case float64:
    		fmt.Printf("v is float64 %f\n", v)
    	default:
    		fmt.Printf("%T:%v type is not acceptable\n", t, t)
    	}
    }
    
    type Person struct {
    	Name string
    }
    
    func main() {
    	TypeChecker(32)
    	TypeChecker(0.5)
    	TypeChecker("hello")
    	TypeChecker(Person{"철수"})
    }
    

    4.変換インタフェース


    4.1インタフェースを特定のタイプに変換

    package main
    
    import (
    	"fmt"
    )
    
    type AInterface interface {
    	DoSomething()
    }
    
    type AStruct struct {
    	Name string
    }
    
    func (a AStruct) DoSomething() {
    	fmt.Println("hello")
    }
    
    type BStruct struct {
    	Name string
    	Age  int
    }
    
    func (b BStruct) DoSomething() {
    	fmt.Println("hello")
    }
    
    func TypeConversion(aInterface AInterface) {
    	b := aInterface.(*BStruct)
    	fmt.Println(b)
    }
    
    func main() {
    	a := &BStruct{"철수", 31}
    	TypeConversion(a) // 타입 변환 성공
        
        	b := &AStruct{"철수"}
        	TypeConversion(b)
        	// > b가 가리키는 타입은 *AStruct이지만 *BStruct로 타입 변환하려고 했기 때문에 런타임 에러 발생
    }
    

    4.2タイプを別のインタフェースに変換

  • 以下の構成の場合、BInterfaceとAInterfaceは互いにタイプを変換できる
  • package main
    
    import (
    	"fmt"
    )
    
    type AInterface interface {
    	DoSomething()
    }
    
    type BInterface interface {
    	DoNothing()
    }
    
    type AStruct struct {
    	Name string
    }
    
    func (a AStruct) DoSomething() {
    	fmt.Println("hello")
    }
    
    func (a AStruct) DoNothing() {
    	fmt.Println("hello")
    }
    
    func TypeConversion(bInterface BInterface) {
    	a := bInterface.(AInterface)
    	fmt.Println(a)
    }
    
    func main() {
    	a := &AStruct{"철수"}
    	TypeConversion(a)
    }
    

    4.3インタフェースの変換時の異常処理方法

    var a Interface
    if t, ok := a.(ConcreteType); ok {
    	...
    }
  • 変換成功
  • t:タイプ変換の結果
  • ok: true
  • 変換失敗
  • t:コンクリートタイプのデフォルト値
  • ok: false