2022/02/13

[golang] interfaceの勉強

go.mod をだいたいわかったつもりでいたけど、go mod tidy してモジュールが見つかりませんと言われると自信がなくなりますな。
はい、忘れるために別の勉強をしましょう。


interface は class とセットで存在するイメージだったのだが、golang には class はない。予約語にもない(どうでもいい話だが、予約語は英語だと"keywords"なので検索しづらい)。
とはいえ、C++ では class と struct が姉妹みたいなものなので違和感はない。

 

プログラミング言語Goの例であげられているのは io パッケージの Writer
短いので貼り付けよう。

type Writer interface {
	Write(p []byte) (n int, err error)
}

Write という名前で、引数として []byte を持ち、戻り値が (int, error) という構成になっていればよいということになる。
ただ、

func Write(p []byte) (n int, err error) {
  return 0, nil
}

みたいな「関数」だとダメだというか、意味が無いと思う。

func (x SomeStruct) Write(p []byte) (n int, err error) {
  return 0, nil
}

のように「メソッド」になっていないとありがたみがないだろう。
メソッドになっているから、複数のメソッドがあるけど interface が同じだから呼び出すことができる、という使い方になるだろう。

 

他の言語では、interface が先にあって、その interface を持つ class を実装することを明示的に書くことが多いと思うが、Go言語は明示的に書かないようになっている。
コードの検索をするときには探しづらいのだが、実装しているときにはあれこれ書かなくて良いので便利なのかもしれない。

明示的に書かなくて良いので、全然 interface を考えずに実装していたメソッドを interface になっているようなつもりで呼ぶことができる。本では「暗黙的に満足される」と書いてある。

 

あとは、宣言した interface 型を組み合わせたり含んだりする interface を作ることもできるということと、中身に何も書かない空インターフェース(empty interface)も作ることができるというくらいか。


というだけにしては本のページが多いので、何か気をつけることがあるのだろう。

 

まず、 empty interface。
これは C言語の voidポインタみたいな感じで何も要求しない interfaceだ。

package main

import (
    "fmt"
)

type dummy1 struct {}
func (d *dummy1) Print(param interface{}) {
    fmt.Printf("dummy1 int: %d\n", param)
}

type dummy2 struct {}
func (d *dummy2) Print(param interface{}) {
    fmt.Printf("dummy2 string: %s\n", param)
}

type dummys interface {
    Print(param interface{})
}

func main() {
    d1 := &dummy1{}
    d2 := &dummy2{}
    d  := []dummys{d1, d2}
    d[0].Print(123)
    d[1].Print("abc")
}

最初は dummy1.Print は param int、dummy2.Print は param string にして「interface{} を引数にしておけばなんでもいけます」みたいな例にしようとしたのだが、それだとコンパイルエラーになった。
interface の中の interface{} は、そのまま interface{} として実装されないといけないようだ。まあ当たり前か。

 

あとは使い方の注意点や型アサーションのことや助言などが書かれている。


empty interface が int や string のような基本型もとれるということは、最初に書いたようなただの関数であっても interface を使って活用させる方法があったりするのだろうか?

でも、あったとしてもあんまりわかりやすいことにはならない気がするので、気にしないことにしよう。