【Go】基本文法メモ⑥(インターフェース)

# 概要
[A Tour of Go](https://tour.golang.org/)の順番に沿ってGoの基本で個人的に学習したことをまとめています。


| No | 記事 |
|------|---------|
|    1  |   [【Go】基本文法①(基礎)](https://qiita.com/k-penguin-sato/items/1d0e1c6b4bf937996cd3)|
|    2  |   [【Go】基本文法②(フロー制御文)](https://qiita.com/k-penguin-sato/items/31b45fd3914797b654f0)|
|    3  |  [【Go】基本文法③(ポインタ・構造体)](https://qiita.com/k-penguin-sato/items/62dfe0f93f56e4bf9157)|
|    4  |  [【Go】基本文法④(配列・スライス)](https://qiita.com/k-penguin-sato/items/daad9986d6c42bdcde90)|
|    5  |   [【Go】基本文法⑤(Maps・ Range)](https://qiita.com/k-penguin-sato/items/a320072fa09502bde3e9)|
|    6  | __〜〜【Go】基本文法⑥(インターフェース)「今ココ」__〜〜     |
|    7  |     [【Go】基本文法⑦(並行処理)](https://qiita.com/k-penguin-sato/items/5b09fa89d8d231bcdac8)    |
|    8  |    [【Go】基本文法総まとめ](https://qiita.com/k-penguin-sato/items/deaeab18aa416496e273)     |

今回は `Interface` に焦点を当てて学習しました。

# Interface(インターフェース)とは？
`Interface(インターフェース)` とはメソッドの型だけを定義した型のことです。
`interface(インターフェース)` を利用することで、オブジェクト指向言語でいうところのポリモーフィズムと同様の機能を実現できます。

# Interface(インターフェース)の定義方法
インターフェースの定義は以下のように記述します（メソッドは複数記述することができます）
インターフェースの定義の内容は、単なるメソッドリストです。

```Golang
type 型名 interface {
    メソッド名1(引数の型, ...) (返り値の型, ...)
      .....
    メソッド名N(引数の型, ...) (返り値の型, ...)
}
```
上記の様にメソッドを羅列していくことでインタフェースを実装(満た)します。


# 空インタフェース

Go言語には、全ての型と互換性を持っている `interface{}型（空インターフェース）` というものが存在しています。
 `interface{}（空インターフェース）` は文字通りゼロ個のメソッドを指定されたインターフェース型のことなので、以下の様に定義する事ができます。

```Golang
interface{}
```
以下の例の様に `interface{}（空インターフェース）` で宣言した変数にはどんな型の値でも代入可能です。

```Golang
var obj interface{}

obj = 0123                                                            // int
obj = "String"                                                       // string
obj = []string{"Python", "Golang", "Ruby"}                          // slice
obj = func greetings(_ string) string { return "Hello World" }     // function
```


# 型アサーション
全ての型と互換性を持っている `interface{}` ですが、`interface{}型` の引数で受け渡された値は、元の型の情報が欠落しています。
そこで、 `型アサーション` は、インターフェースの値の基になる具体的な値を利用する手段を提供します。
型のアサーションには以下の構文を使用します。

```Golang
value := <変数>.(<型>)
```
この文は、インターフェースの値 `<変数>` が具体的な型 `<型>` を保持し、基になる `<型>` の値を変数 `value` に代入することを主張します。
また、以下の様にする事で、1番目の変数には型アサーション成功時に実際の値が格納され、2番目の変数には型アサーションの成功の有無（true/false）が格納されます。

```Golang
value, ok := <変数>.(<型>)
```
実際に以上の方法で型のアサーションが出来る事を確認します。

```Golang
func main() {
	var intface interface{} = "hello"

	variable := intface.(string)
	fmt.Println(variable) //=> hello

	variable, ok := intface.(string)
	fmt.Println(variable, ok) //=> hello true

	float, ok := intface.(float64) 
	fmt.Println(float, ok) //=> 0 false
	//格納失敗が、成功したかの有無を確かめるokが存在するのでエラーにはならない。
	
	float = intface.(float64) 
	fmt.Println(float) //=> panic: interface conversion: interface {} is string, not float64
    //成功したかの有無を確かめるokが存在しないのでエラーが発生する。
}
```
上記の例ではインターフェースは `string` として型付けされているので、それと異なる `float64` 等を `<型>` 部分に書くとエラーが発生します。
（成功したかの有無を確かめるok（左辺に２番目の変数）が存在するのでエラーにはならない。）

# 型switch 
データの型判定は `switch` 文でも行うことができます。Go 言語では、これを `型 switch` といいます。
以下の様に `型switch` を書く事ができます。

```Golang
switch v := x.(type) {
case 型1: ...  // v は型1 の値になる
case 型2: ...  // v は型2 の値になる
    ...
default: ... 
}
```
`型switch` では上記の様に `switch` の後ろに型アサーション `v := x.(type)` を書き、`case` に型を指定します。

以下で実際の使用例を確認してみましょう。

```Golang
func do(i interface{}) {
	switch variable := i.(type) {
	case int:
		fmt.Println(variable)
	case string:
		fmt.Println(variable)
	default:
		fmt.Println("Default")
	}
}

func main() {
	do(23) //=> 23
	do("hello") //=> hello
	do(true) //=> Default
}
```

上記の様に書く事で、データの型判定を行いより柔軟に型のアサーションを実現する事が可能です。

# 構造体にインターフェースの実装

以下の様に書く事で構造体にインターフェースを実装する事ができます。

```Golang
func (引数 構造体名) 関数名(){
     関数の中身
}
```

実際に以下のコードから上記の方法でインターフェースを実装できることを確認します。

```Golang
type People interface {
	intro()
}

type Person struct {
	name string
}

//構造体PersonがインターフェースPeopleを実装した事を意味します。
func (arg Person) intro(){
   	fmt.Println(arg.name)
}

func main() {
	bob := Person{"Bob"}
	bob.intro() //=> Bob
}
```

# Interface(インターフェース)実例
以下のコードから `Interface(インターフェース)` とは何か、より具体的に捉えます。
以下の例では `Person` と `Person2`という構造体があり、各構造体に `intro()` メソッドが定義されており、各構造体が `intro()` を実行するための `IntroForPerson()` `IntroForPerson2()`が存在しています。

```Golang
type Person struct {} //Person構造体
type Person2 struct {} //Person2構造体

//Person構造体のメソッドintro()
func (p Person) intro() string{ 
    return "Hello World"
}

//Person2構造体のメソッドintro()
func (p Person2) intro() string{
     return "Hello World"
}

//Person構造体のメソッドintro()を実行するメソッド
func IntroForPerson(arg *Person){
	fmt.Println(arg.intro())
}

//Person2構造体のメソッドintro()を実行するメソッド
func IntroForPerson2(arg *Person2){
	fmt.Println(arg.intro())
}

func main(){
  bob := new(Person)
  mike := new(Person2) 
  
  IntroForPerson(bob) //=> Hello World
  IntroForPerson2(mike) //=> Hello World
}
```

このままでは同様の動きをする`IntroForPerson`と`IntroForPerson2`メソッドが存在しており冗長です。
そこで以下のコードの様に `Interface(インターフェース)` に括り出してみましょう。

```Golang
type Person struct {} //Person構造体
type Person2 struct {} //Person2構造体

type People interface{
    intro()
}

func IntroForPerson(arg People) {
     arg.intro();
}

//Person構造体のメソッドintro()
func (p *Person) intro() { 
    fmt.Println("Hello World")
}

//Person2構造体のメソッドintro()
func (p *Person2) intro() {
     fmt.Println("Hello World")
}

func main(){
  bob := new(Person)
  mike := new(Person2) 

  IntroForPerson(bob) //=> Hello World
  IntroForPerson(mike) //=> Hello World
}
```
これによって関数をまとめる事ができ、より簡潔なコードとなりました。


# 参考
[My Journey of Go⑥](https://k-blog0130.herokuapp.com/posts/20)
[インタフェースの実装パターン #golang](https://qiita.com/tenntenn/items/eac962a49c56b2b15ee8)
[Go言語 - interfaceを触ってみる](https://blog.y-yuki.net/entry/2017/05/07/000000)
[はじめてのGo言語(インターフェース)](http://cuto.unirita.co.jp/gostudy/post/interface/)
[お気楽 Go 言語プログラミング入門](http://www.geocities.jp/m_hiroi/golang/abcgo09.html)
[A Tour of Go](https://tour.golang.org/list)
[覚えたら書く](https://blog.y-yuki.net/entry/2017/05/08/000000)