LoginSignup
0
0

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

Last updated at Posted at 2023-06-22

はじめに

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

目次

  1. Interfaces : インターフェース
  2. 空インターフェース
  3. 型アサーション
  4. 参考文献

Interfaces : インターフェース

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

インターフェースの定義方法は以下です。

type 型名 interface {
    メソッド名1(引数の型) (返り値の型)
    メソッド名2(引数の型) (返り値の型)
}

では、このインターフェースがどう使われるのか?
もう少し具体的に説明していきます。

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 {〜 の部分ですね。
構造体(Japan)がインターフェース(Country)を実装したことを意味しています。

幾つか使用例をご紹介します。
まずは、メソッドへのインターフェースの実装です。定義方法は以下です。
 ※ メソッド名 : インターフェース内のメソッド名と合わせる
 ※ 引数の型 : インターフェース内のメソッドの型と合わせる

func (引数 レシーバー名) メソッド名() 引数の型 {
    メソッドの中身
}
// Country インターフェース
type Country interface {
    Language() string
}

// 構造体 Japan
type Japan struct {}

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

また、インターフェースを代入した変数へ構造体を代入した変数を代入(構造体(Japan)がインターフェース(Country)を実装)することで、インターフェースから構造体が持つメソッドを呼び出すパターンもあります。

// Country インターフェース
type Country interface {
    Language() string
}

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

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

// Country インターフェースから Language メソッドを呼び出す
fmt.Println(country.Language())

上記のように、最低限のメソッドを各インターフェースで定義することで、インターフェース単位で呼び出すことができるメソッドを明確化・区別することができます。

空インターフェース

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

空インターフェースの定義方法は以下です。

interface{}

どんな型でも代入可能です。

var i interface{}

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

型アサーション

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

型アサーションの定義方法は以下です。

value := 変数.()

以下、型アサーションの使用例です。
「具体的な型を指定」の意味がわかるかと思います。
ちなみに、データの型判定を行うことをアサーションと言います。

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の型とインターフェースの値の型を比較します。

main.go
switch v := i.(type) {
case 型1: ...  // v は型1 の値になる
case 型2: ...  // v は型2 の値になる
    ...
default: ... 
}

以下、型アサーションの使用例です。
インターフェースの値iの型とcaseで指定された型を比較しています。

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 Tour of Go
Go言語 インターフェース
Goのinterfaceがわからない人へ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0