golangのインターフェースがイマイチ理解できず泣きそう
こんにちは、つじたく(@Tsuji_Taku50)です。
golangのインターフェースについて自分の理解が及ばず泣きそうです。
使いこなせればめちゃくちゃ便利なんでしょうが、理解できない人にとっては使いどころが分かりません。
golangのインターフェース
様々なインターフェースについての記事を見たのですが、書いてあることはほぼほぼ同じです。(そりゃそうですよね)
「golangのインターフェースはメソッドを定義しているもので、実装は別にある。」
「インターフェースが定義しているメソッドを全て実装してればインターフェースをして振る舞うことができる」
この時点で既に頭がパンクしそう泣
しかし、めげずに他の人の記事を何度も読み返したり自分でコードを写経したりしました。
インターフェースの使いどころ
自分なりの写経したり、参考になりそうな記事を読んだりしたのですが
結果としてインターフェースの使いどころが分かりません泣
例えば急いで学ぶGo lang#6 インターフェイス | Developers.IOに書かれているサンプルコードですが
// 構造体定義 type MyCar struct { name string speed int } // runメソッド func (u *MyCar) run(speed int) string { u.speed = speed return strconv.Itoa(speed) + "kmで走ります" } // stopメソッド func (u *MyCar) stop() { fmt.Println("停止します") u.speed = 0 } // MyCar構造体はCarインターフェースのメソッドを全て実装しているので // Carインターフェースとして振る舞うことが可能 func main() { myCar := &MyCar{ name:"マイカー", speed:0, } var i Car = myCar fmt.Println(i.run(50)) i.stop() }
このコード自体はまぁ理解できるのですが、
記事には「新しく構造体を追加した場合でも、runとstopさえ定義していれば、Car型として扱うことができます。」と書かれています。
ただ僕からすると、
え・・・・?それで・・・・?それって何がいいの・・・状態です。
新しく追加した構造体がCar型として振る舞うことができる = 何か利点になる
ということが理解できない。。
逆に理解できたこともあります。
それは「インターフェースにはどんな型でも代入可能」ということです。
// 空インターフェース // 空インターフェース変数には、どんな型でも代入可能 var i interface{} // int型を代入してみる i = 10 // 型を判定して処理する switch value := i.(type) { case int: fmt.Println("int : ",value) case string: fmt.Println("string : ",value) case bool: fmt.Println("bool : ",value) default: fmt.Println("other") }
上記のような感じです。OSSを見ていても頻繁に使われている気がします。
例えばgo-githubリポジトリの下記箇所の引数にもinterfaceが使われています。 go-github/github.go at a0c13e8ec49ea2a7f412417257aabeba0477f6d1 · google/go-github · GitHub
それ以外も箇所にも頻繁に使われているようです。
ただ、引数の型がちゃんと決まっている時にはintなりstringなりを指定したほうが良いような気がします。
やたらめったら引数にinterfaceを使うと型が限定できなくてコードを読む人間にとっては苦痛になりそうです。
まとめ
この記事に書いたのはインターフェースの使い方のほんの一部です。
ただそのほんの一部の使い方すら理解できずに苦しんでいます。
3年ほど前にJavaを勉強知ているときにもあった感覚ですがひたすらコードと向き合うしかない気がしています。
ので、まだまだgolangと向き合ってコードを読もうと思います。
golangインターフェースの写経をGithubにも上げてます。 github.com
おわり!!
参考URL
参考にさせてもらった記事のURLを載せておきます。
ものすごく丁寧に書かれているので理解が早い人はこれを読むだけでインターフェースのことを理解できるのではないでしょうか。
羨ましい・・・