TL;DR
-
interface
の管理がちょっと辛かった - pub/prvが大文字小文字は罠
-
enum
が分かりづらい - 後置型宣言好き
- DB系つらい
- ロガーいいのありませんか!!!!!
Kloudハッカソン#3 コードでつながる夏の友情物語に出場しました。そこでGoをガッツリ書く機会をもらったので触った感想を書きたいと思います。
Context: 普段はRustやTSを書く人間なので、その視点からの感想になります。
interface
について
interface
はGoにおける多態性を実現するための手段の一つで、「外部から見た振る舞い」の一致するものを内部の内容や実装に関わらず同じものとして扱う機能です。
(あまり意味がない比喩を使うが)「掃除」を依頼するサービスがあった時、部屋がキレイになる結果がほしいのであって。手段は何でもいいという場合、家政婦を雇って掃除をしてもらうのもいいですし、ルンバのような掃除ロボットを使用するのも手段の一つでしょう。このような例においては、汚い部屋を掃除する機能を持つものであれば何を使っても良い場合が存在します。つまり、clean()
というメソッドを持つようなクラスや構造体を提供すればプログラム的にはOKなのです。
package main
import (
"fmt"
)
type Cleaner interface {
Clean()
}
type Room struct{}
func (r *Room) RequestClean(cleaner Cleaner) {
cleaner.Clean()
}
type Robot struct{}
type Maid struct{}
func (r *Robot) Clean() { fmt.Println("掃除したのはロボットです。") }
func (m *Maid) Clean() { fmt.Println("掃除したのは家政婦です。") }
func main() {
dirtyRoom1 := Room{}
dirtyRoom2 := Room{}
robot := &Robot{}
maid := &Maid{}
dirtyRoom1.RequestClean(robot)
dirtyRoom2.RequestClean(maid)
}
掃除を依頼するrequestClean
の定義では、引数にinterface
であるCleaner
型を要求しています。これによりinterface
の持つclean()
メソッドを定義する構造体はこのCleaner
インターフェースを「実装」しているとみなすことができ、引数に取ることができます。
Goのinterface
は、RustのTraitのように明確にコードで明示するのではなく、interface
の持つ関数と同名のメソッドをすべて実装していればinterface
の実装とみなすので、そこを気をつけないといけないのが少し大変違和感を覚えました。
一応この様なエラーは出してくれるので確認はできますが、それでもこのinterface
を実装するぜ!みたいな書き方の方が安心できるという考えがあります
cannot use robot (variable of type *Robot) as Cleaner value in argument to dirtyRoom1.RequestClean: *Robot does not implement Cleaner (missing method Clean)
ロガーが辛かった
動かしたときに、大量のログを吐いてしまい原因を探るのに苦労したのが辛かったです。ちゃんとした仕様を理解せずにロガーを使うととんでもないことになるなぁという反省をしました。これに関してはRustがすごい優秀なのも余計にあるかもしれません
public/privateは大文字小文字で判定される
個々人で決めるような思想を言語側で縛られている感覚があるのと、視認性に頼るしか無いためやめてほしいなと思いました()