旅行しながら働く ムラサメ研究所社長ブログ

主にゲームやプログラミングのログ

Golang 試食 Part1

仕事で1か月間に新しく6言語を使ったのだが、その中で最も触ったのがGo
色々と想像と違ってたので、Goを勉強始めるあたりから書いていく

使う前の印象(全然間違えてた)

天才技術者エリート集団 Googleの作った最高の言語
コンパイル言語で、C言語並みの実行速度と スクリプト言語並みの作業効率
ゴルーチン等の、高速な非同期をつかった次世代Web言語
ひゃっほ~~

目的

DevOps目的で、チャットBOTを作る
プロジェクトに使う各種ツールのURLやディレクトリを教えたり
新人が入った際のアカウント追加をサポートしたり
ソースコードのCIや ビルドを行ったり
Deployを行ったり
メトリクスのアラート出したり
・・・
色々なオペレーションをするためのサンプル

ファーストターゲット

Slackで動くBOT
AWSのECR上にUpされたコンテナのリスト表示、Tag指定でDeployする

SlackBot

Slack側の設定

Slack側の設定はほかの人のブログみてもらおう

全容

今回は github.com/nlopes/slack を利用する
ので パッケージで上記を指定する
Golangコンパイルエラーが厳しく、使ってないものをimportするとコンパイルしてくれない

main.go

package main

import (
    "log"
    "net/http"
    "os"
    "github.com/kelseyhightower/envconfig"
    "github.com/nlopes/slack"
)

type envConfig struct {
    Port              string `envconfig:"PORT" default: "3000"`
    BotToken          string `envconfig:"BOT_TOKEN" required: "true"`
    BotID             string `envconfig:"BOT_ID" require: "true"`
    ChannelID         string `envconfig:"CHANNEL_ID" require: "true"`
}

func main() {
    os.Exit(_main(os.Args[1:]))
}

func _main(args []string) int {
    var env envConfig
    if err := envconfig.Process("", &env); err != nil {
        return 1
    }
    client := slack.New(env.BotToken)
 
    slackListener := &SlackListener{
        client:    client,
        botID:     env.BotID,
        channelID: env.ChannelID,
    }

    go slackListener.ListenAndResponse()

    if err := http.ListenAndServe(":"+env.Port, nil); err != nil {
        log.Printf("[Error] %s", err)
        return 1
    }
    return 0
}

slackListenerは後で

package

package名mainは特殊である。
このパッケージのみ エントリーポイントとしてmain関数が機能する

import

importはとても便利。今までGoを使ってパッケージの依存関係なので悩んだことはなかった
(ただし duplicate importは 非常にダメだ・・・ ) Githubリポジトリから直接持ってこれるのも素晴らしい
さすがGoogle

コード所感

文法は慣れるしかないが、C言語Java等のメジャーな文法とは大きく変えてきている
全体的にGoはダックタイピングだ 変数や関数名の頭を小文字にすると外部パッケージからアクセスできないので、Publicな関数や変数は大文字スタートにする
また、C言語では暗黙的型変換されるもの(int32, int64 なども)も明示的にキャストしなければエラーである

エントリポイント

mainのところはおまじないとして なんとなく意味わかるでスルーしよう

envconfig

main_ 実質のメイン
envconfigは上記Githubからのパッケージで、環境変数を構造体にマッピングしてくれる

err := envconfig.Process("", &env);

envconfig.Process にて環境変数が設定されていれば構造体に入る
:= は、変数の宣言、定義、代入である(関数内でのみ使用できる) 例えば
hoge := func() は
var hoge = func()
とだいたい同等である
ただ、使った感じ微妙にスコープが違う

nlopes/slack

client := slack.New(env.BotToken) にて、nlopes/slackのインスタンスを作成する
もちろん env.BotTokenは、環境変数 BOT_TOKENに入っているトークンだ

構造体作成

   slackListener := &SlackListener{
        client:    client,
        botID:     env.BotID,
        channelID: env.ChannelID,
    }

来た。。これは構造体の作成(new)を行っている
GoではClassは無く C言語のように 構造体を作成しそこにデータを保存し、関数に構造体を渡す
つまり 全くオブジェクト指向じゃない!
そして 構造体の作成方法が何種類もある

type Hoge struct{
  Name string
  Age int64
}

// newの場合は 宣言と同時に初期化できない
hoge1 := new(Hoge)
hoge1.Name = "HOGE"
hoge1.Age = 10

// &でも構造体を作成できる
hoge2 := &Hoge
hoge2.Name = "HOGE"
hoge2.Age = 10

// &は定義時に初期化可能
hoge2 := &Hoge{ Name: "HOGE", Age: 10 }

// 構造体のフィールド名省略可能
hoge2 := &Hoge{ "HOGE", 10 }

つまり &を使ったものだけ覚えておけば良いと今の時点では思っている

Listen

   go slackListener.ListenAndResponse()
        err := http.ListenAndServe(":"+env.Port, nil)

go の部分が Golangの特徴である ゴルーチン
ゴルーチンは非同期で実行されるため、 slackListener.ListenAndResponse() が終了しなくても
即座に次の行へ制御がいき http.ListenAndServeが実行される

slackListenerの中身は後で勉強するとして、大雑把にいうと WebSocketを待機していて、Slcakとアクセスをする
http.ListenAndServeにて Listenを行う

この時点の感覚

Goのコードはオブジェクト指向ではなく、予想以上に低レイヤーであった
C言語を書きやすくした Better C言語である
ゴルーチンは非同期をわかりやすく解決していて使いやすそう
ただ 予想より難しい言語で、PHPerが移住する場所としては不適切ではないか?
Web言語として優れているとは現時点ではいいにくい(あくまで Better C)