仕事で使いそうだったので勉強してみた感想とか。振り返りとか。
学習履歴
- Tour of go をやって Go を完全に理解する。
- いろいろ作った。
- みんなの Go 言語を読む。
- Effective Go を読んでさらに理解を深める。← いまここ
触ってみて
コンパイルが早い
Scala を書いてるときのいわゆる 待ち みたいなのを感じなくなったかも(コンパイルとかユニットテストとか)。Mac も大きな声で泣き叫んで発熱することもなくなった感。
組み込みのAPIが充実
用意されているものが優秀なので、簡易なHTTPサーバーを作るのにフレームワークなどを使う必要はなさげ(個人差ありそう)。
実行環境を選ばない
go build
で生成したバイナリはランタイムに依存しないので配布しやすい。コンテナを作るときはマルチステージビルドでバイナリだけ入れとくとか巷で良く見かける。
FROM golang:1.13-buster as builder
RUN mkdir /app
WORKDIR /app
COPY src ./src
RUN go build -o /main ./src/cmd/*.go
FROM debian:stretch-slim
COPY --from=builder /main .
ENTRYPOINT ["./main"]
軽量のコンテナは、CA証明書が入ってなかったりするから Image に固めるアプリケーションが HTTP Client 実装してたりしたときは注意。
構文に関して
迷いのなきエラーハンドリング
変数に入れて nil かどうかを愚直に評価していく。とにかくこれな印象。
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}
いわゆるガード節を書いていくので else とかは書かないほうが良い。
f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
f.Close()
return err
}
codeUsing(f, d)
たまにはモナドが恋しいときもある。
命名でパッケージ外からの可視性が決まる
先頭文字を大文字にすることで他パッケージからの参照が可能となる。
小文字だと参照不可。最初これ知らなくてハマった。
package model
type T_horikoshi struct {
Name string
}
type t_horikoshi struct {
name string
}
package main
func Ref() {
t := domain.T_horikoshi{Name:"t_horikoshi"}
//t := domain.t_horikoshi{name:"unexported..."}
fmt.Print(t)
}
リソースのクローズとかやってくれる Defer が便利
リソースのクローズ処理のため Defer という仕組みが用意されている。
関数内に宣言しておくと最後まで処理を行った後に自動的に実行してくれるのでので便利。
type ExchangeRate struct {
Quotes []Quote
}
type Quote struct {
High string
Open string
Bid string
CurrencyPairCode string
Ask string
Low string
}
func GetExchangeRatePerYen() (rate *ExchangeRate, err error) {
resp, err := http.Get("https://www.gaitameonline.com/rateaj/getrate")
if err != nil {
return nil, err
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.Fatal("close resources", err)
}
}()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
rate = new(ExchangeRate)
if err := json.Unmarshal(bytes, rate); err != nil {
return nil, err
}
return rate, nil
}
resp.Body.Close()
が error
を返すので無名関数で実装しなければならない。
interface を実装する
Scala脳に染まってたので extends どうやるんやとか思ってたら、interface に定義したメソッドを実装したらその時点で継承が完了するみたい。
世間でダックタイピングと呼ばれているもの。
↑これわたし勉強不足だったのですが、Structural typing と呼ばれるもので構造の宣言や定義によって型の互換性や透過性を保証し、型チェックを行わない Duck typing とは全くもって対をなすというものでした。
@c-yan さんコメントありがとうございます。
package main
import "fmt"
type Human interface {
Call() string
}
func VoiceChecker(h Human) {
fmt.Print(h.Call())
}
type Animal struct {}
func (a Animal) Call() string {
return "bau!bau!"
}
type Insect struct {}
func (i Insect) Call() string {
return "paru!paru!"
}
func main() {
VoiceChecker(Animal{})
VoiceChecker(Insect{})
}
つづく...
そのうちに書きます。