Go 基本文法【インターフェース編】

## はじめに
Goの基本文法シリーズ、今回で最後となりました。
ラストはGo学習者が混乱すると評判の<b>「Interfaces ： インターフェース」</b>についてです。

## 目次
1. [Interfaces ： インターフェース](#interfaces--インターフェース)
2. [空インターフェース](#空インターフェース)
3. [型アサーション](#型アサーション)
4. [参考文献](#参考文献)

## Interfaces ： インターフェース
インターフェースとは、メソッドの塊のことです。
メソッドの型だけを定義した型を```interface 型```と言います。

インターフェースの定義方法は以下です。
```golang
type 型名 interface {
    メソッド名1(引数の型) (返り値の型)
    メソッド名2(引数の型) (返り値の型)
}
```
では、このインターフェースがどう使われるのか？
もう少し具体的に説明していきます。
```golang:main.go
package main

import "fmt"

// Country インターフェースを生成
type Country interface {
	// Language　メソッドを持たせる
    Language() string
}

// 構造体 Japan を生成(型：Japan)
type Japan struct {}

// 構造体 Japan が Country インターフェースを実装
func (c Japan) Language() string {
    return "Japanese"
}


// 構造体 USA を生成
type USA struct {}

// 構造体 USA が Country インターフェースを実装
func (c USA) Language() string {
	return "English"
}

func main() {
	// Country インターフェース型のスライスを生成
	countries := []Country{Japan{}, USA{}}

	// 生成したスライスに格納された値を反復処理で出力
	for _, country := range countries {
    	fmt.Println(country.Language())
	}
}
```
↑で混乱するとすれば、```func (c Japan) Language() string {〜``` の部分ですね。
<b>構造体(```Japan```)がインターフェース(```Country```)を実装</b>したことを意味しています。

幾つか使用例をご紹介します。
まずは、<b>メソッドへのインターフェースの実装</b>です。定義方法は以下です。
　※ メソッド名 ： インターフェース内のメソッド名と合わせる
　※ 引数の型 ： インターフェース内のメソッドの型と合わせる
```golang
func (引数 レシーバー名) メソッド名() 引数の型 {
    メソッドの中身
}
```
```golang
// Country インターフェース
type Country interface {
    Language() string
}

// 構造体 Japan
type Japan struct {}

// 構造体 Japan が Country インターフェースを実装
func (c Japan) Language() string {
    return "Japanese" // => Japanese
}
```
また、インターフェースを代入した変数へ構造体を代入した変数を代入(<b>構造体(```Japan```)がインターフェース(```Country```)を実装</b>)することで、<b>インターフェースから構造体が持つメソッドを呼び出す</b>パターンもあります。
```golang
// Country インターフェース
type Country interface {
    Language() string
}

var country Country // Country インターフェースを変数へ代入
var language Japan // 構造体 Japan を変数へ代入

country = language // Country インターフェースへ構造体 Japan を代入

// Country インターフェースから Language メソッドを呼び出す
fmt.Println(country.Language())
```
上記のように、最低限のメソッドを各インターフェースで定義することで、<b>インターフェース単位で呼び出すことができるメソッドを明確化・区別</b>することができます。

## 空インターフェース
全ての型と互換性を持つ```interface{}型（空インターフェース）```というものもあります。
文字通りゼロ個のメソッドを指定された interface 型のことです。

空インターフェースの定義方法は以下です。
```golang
interface{}
```
どんな型でも代入可能です。
```golang
var i interface{}

i = 100                                          // int
i = "Interface"                                  // string
i = []string{"Go", "Ruby", "PHP"}                // slice
i = func say(_ string) string { return "Hello" } // function
```

## 型アサーション
```interface{}```で引き渡された値というのは元の型の情報が欠落しています。
型アサーションは、インターフェースの値に<b>具体的な型を指定</b>・利用することができます。

型アサーションの定義方法は以下です。
```golang
value := 変数.(型)
```
以下、型アサーションの使用例です。
<b>「具体的な型を指定」</b>の意味がわかるかと思います。
ちなみに、データの型判定を行うことを<b>アサーション</b>と言います。
```golang:main.go
package main

import "fmt"

func main() {
    // 空インターフェースを生成
	var i interface{} = "hello"

    // 型を持たない空インターフェースの型として string 型を指定、変数へ代入
	s := i.(string)
	fmt.Println(s) // => hello

    // 変数 i が string 型かどうかアサーション
    // string 型のため true
	s, check := i.(string)
	fmt.Println(s, check) // => hello true

    // 変数 i が float64 型かどうかアサーション
    // float64 型でないため false
	f, check := i.(float64)
	fmt.Println(f, check) // => 0 false

    // この時点でインターフェース　i　は string 型指定されている
    // float64 型として指定・利用しようとするとエラーになる
	f = i.(float64)
	fmt.Println(f) // => panic: interface conversion: interface {} is string, not float64
}
```

## 型switch
データの型判定は、型switch でも可能です。

型switchの定義方法は以下です。
以下の様に switch の後ろに型アサーション```v := i.(type)```を書き、```case```に型を指定します。```case```の型とインターフェースの値の型を比較します。
```golang:main.go
switch v := i.(type) {
case 型1: ...  // v は型1 の値になる
case 型2: ...  // v は型2 の値になる
    ...
default: ... 
}
```
以下、型アサーションの使用例です。
インターフェースの値```i```の型と```case```で指定された型を比較しています。
```golang
package main

import "fmt"

func do(i interface{}) {
	switch v := i.(type) {
	case int:
		fmt.Printf("Twice %v is %v\n", v, v*2)
	case string:
		fmt.Printf("%q is %v bytes long\n", v, len(v))
	default:
		fmt.Printf("I don't know about type %T!\n", v)
	}
}

func main() {
	do(21) // => Twice 21 is 42
	do("hello") // => "hello" is 5 bytes long
	do(true) // => I don't know about type bool!
}
```
上記の通り、型switch により柔軟に型アサーションを行うことができます。

## 参考文献
<a href="https://go-tour-jp.appspot.com/">A Tour of Go</a>
<a href="https://recursionist.io/learn/languages/go/oop/interface">Go言語 インターフェース</a>
<a href="https://qiita.com/rtok/items/46eadbf7b0b7a1b0eb08">Goのinterfaceがわからない人へ</a>