[golang(Go言語)]interface入門
Go言語のinterface(インターフェース)の使い方を学ぶにあたって、構造体とメソッドの解説が必要になるので、合わせて記載しています。また、interfaceとinterface{}型は見た目が被っていてややこしいので、両者の違いも最後に説明します。
構造体とメソッド
構造体とは
構造体は、いくつかの変数を保持するデータのまとまりのことです。Javaで言うとフィールドをいくつか持っているクラス、がイメージに近いと思います。
//packageとimportは省略 // 定義 // 基本的に先頭は大文字。他packageから利用するため。 type Person struct{ Age int // 基本的に先頭は大文字。変数名.フィールド名でアクセスするため。 Name string MyNumber string } func main() { // p := Person{} または var p Person とすることもできる。 p := Person{ Age : 20, } // 構造体型の変数の宣言時に指定しなかったフィールドにはゼロ値が入る(ゼロ値はint型なら0、string型なら""の空文字) fmt.Println(p.Name) // 出力は""(空文字です) // 変数名.フィールド名で代入可能 p.Name = "太郎" fmt.Println(p.Name) // 出力は"太郎" }
コード例に説明も合わせました。イメージは掴めたでしょうか?
メソッドとは
Go言語には関数とメソッドという似たものが存在します。定義の違いは、レシーバーが無いのが関数、有るのがメソッドです。例えば上のコード例内のfunc main()は、レシーバーが無いので関数です。レシーバーとメソッドに関しては、下のコード例をご覧ください。
func main() { p := Person{ Name : "太郎", } fmt.Println(p.getName) // "太郎" } // (h Person)部分がレシーバーの指定です。 // hの部分は何の文字でも良いです。宣言した変数名と合わせる必要はありません。 // Personの部分には構造体名を指定します。 func (h Person)getName()(string) { // レシーバーをメソッド内で利用できます。 return h.Name }
上記のように、メソッドによって、構造体に関する処理を定義することができます。。
インターフェース
本題のインターフェースです。
構造体はフィールドの集まりでしたが、インターフェースはメソッドの集まりです。
構造体とは定義の方法が大きく異なります。インターフェースで定義したものは構造体と同じように変数名 := インターフェース名 とはできません。
手順としては、
- interfaceの定義
- interfaceを実装する構造体の定義
- interfaceで定義したメソッドを、構造体をレシーバーにして全て実装
// interfaceの定義 type PersonRepository interface{ Get(myNumber string)(p Person) } // interfaceを実装したい構造体 type personRepository struct{ // DBのコネクションなどを定義する } // personRepository型変数を他のpackageからこの関数で取得し、その変数に対するメソッドを利用します。 // 本番では引数にDBコネクションなどを引き渡して、それらをフィールドに持つpersonRepository構造体を返します。 func NewPersonRepository()(PersonRepository){ return personRepository{} } // interface内のメソッドを実装します。interfaceで定義したメソッドと関数名・引数・戻り値が等しいメソッドを、全て用意しないとコンパイルエラーになります。 func (r personRepository)Get(myNumber string)(p Person){ // DBから取得する処理を記述 }
interface{}
interface{}はintやstringなどの仲間で、データ型の一種です。
引数や戻り値でinterface{}型の変数を指定すると、どんな型の値でもその変数として受け渡しできます。型を指定されていた方がぱっと見分かりやすいので、使う機会は限られると思います。が、一応コード例を載せておきます。
func main() { s := test() // interface{}型変数名.(型名)で元の型の変数と成功可否を取れる g, isString := s.(string) if isString { fmt.Println(g) } } func test()(interface{}) { d :="太郎" return d }