go言語の始め方(1)
Google独自言語使いとしてもう一つのGoogle言語であるGo言語を紹介します。 コンパイル型言語のめんどくささがツライと思って敬遠してたけど、 触ってみたらびっくりするほどシンプルでLLっぽく使えるし、 静的型言語の恩恵にも預かれちゃうなかなか楽しい処理系だと思いました。
Go言語の概要
ネイティブコードにコンパイルして動く
- go処理系はすでにかなりのプラットフォームをサポート
- x86/amd64/ARM、Win/OS-X/Linux/Android/BSDなどなど
- コンパイルがDelphiを連想させるほどばかっ早い
- どのプラットフォームでも「go run ソース」ってすればさっくり動く
- 使用感はスクリプトを実行しているのとあまり違わない
- ビルドすると不要なコードはすべて取り除かれるのはLL言語と違うところ
- 出力されるバイナリは総じて少し大きめだが他に依存するライブラリが無い
- ただしC拡張パッケージを使うと依存ライブラリが必要になる
シンプルに必要十分な言語仕様
- 1つファイルに1つの名前空間が割り当て(Pascalライク)
- 構造体をオブジェクトライクに扱うベターCな言語
- 継承機構、オーバーロード、オーバーライドを捨てたフラットな型システム
- 追記: mixinやオーバーロードができるそうです!!
- 構造体に無名構造体タイプを入れるとMixinされるみたい。
- 引数や返値を厳格に定義したり、インターフェース定義で縛るDbC的な設計
- 暗黙の型変換ができないので曖昧な型のトラブルが抑えられる
- 親パッケージ名は省略できないのでパッケージソースを遡るのが容易い
- なんでも明示する設計思想。Pythonのselfに相当するものもある
- コード記述量と予想される処理量の乖離が少ない。(ここはC言語的な感触)
非同期サポートを標準で備えている
- クロージャを書ける
- 軽量スレッドgoroutinが言語仕様にある
- CSP向けチャネルのchanが言語仕様にある
- goroutin+chanでジェネレータ的な処理も書ける
- goroutinが数十バイトのリソースで作れるので数十万スレッドとか使える
バッテリーインクルード
- テスティング、ベンチマーク、パッケージマネージャ、ドキュメントシステム
- ビルドシステム、クロスビルドサポート、コードフォーマッタ
- json、http、crypto、compress、mathなどなど
- OpenSSL相当の機能も内包してる
- image処理ライブラリが標準でバンドル
- jsonrpcなどのモダンなプロトコルを標準でサポート
- 準標準パッケージにWebsocketsやSPDYもある
- C拡張作成支援も良く出来てる
モダンなパッケージマネジメント
- 「go get リポジトリ名」でリモートリポジトリのパッケージをローカルインストール出来るよ!
- リモートリポジトリはcode.google.comやgithub、bitbucketなどもサポート。
- タグ指定でのインストールもできる。
Go言語環境の構築
Mac OS-Xの場合
- 本体のセットアップ:
- brew install go
- デバッガインストール:
- brew install https://raw.github.com/Homebrew/homebrew-dupes/master/gdb.rb
- gdbにコード署名を関連付け( 参考 )
- IDEのセットアップ:
- liteideのプロジェクトページ -> liteidex18.1.macosx-10.6-webkit.dmg
- go get github.com/nsf/gocode
環境変数とパッケージの管理
設定推奨の環境変数は2つ
- GOROOT : golangインストールルートフォルダ
- GOPATH : golangのユーザーパッケージのインストールフォルダ
goツールからの相対でGOROOTや、GOPATHのデフォルトが決まってるみたいだけど、 出来れば設定したほうがいいらしい。go1.0まではGOROOTとGOPATHを同じに出来たけど、 1.1からは分離しないとNGになってる。
GOROOTツリー
$GOROOT(省略すると`which `)
├── bin <- goなどのコアツール
├── pkg
│ └── darwin_amd64 <- プラットフォーム名(Linuxならlinux_amd64など)
│ └── *.a <- パッケージのビルド済みライブラリのインストール先
└── src
└── pkg
└── //*.go <- システムパッケージ群
GOPATHツリー
$GOPATH
├── bin <- 実行可能アウトプットのインストール先
├── pkg
│ └── darwin_amd64 <- プラットフォーム名(Linuxならlinux_amd64など)
│ └── *.a <- パッケージのビルド済みライブラリのインストール先
└── src
└── pkg
└── //*.go <- ユーザーパッケージインストール先
で、$GOROOT/binや$GOPATH/binも環境変数PATHに追加しておくといいね。
LiteIDEではプラットフォームを選択して「Edit Environ」ボタンで、GO環境設定が編集できる。 上記の内容を踏まえて以下のように項目を埋めておこう。
darwin64の例
# native compiler drawin amd64
GOROOT=/usr/local/Cellar/go/1.0.3 #<- brewによるインストール先
GOBIN=
GOARCH=amd64
GOOS=darwin
CGO_ENABLED=1
GOPATH=$HOME/GoLang #<- ユーザーパッケージパス
PATH=$GOBIN:$GOROOT/bin:$PATH
LITEIDE_GDB=gdb #<- brewでインストールしたgdbの名前
LITEIDE_MAKE=make
LITEIDE_TERM=/usr/bin/open
LITEIDE_TERMARGS=-a Terminal
LITEIDE_EXEC=/usr/X11R6/bin/xterm
LITEIDE_EXECOPT=-e
結果
以上の設定を完了するとLiteIDEが動く。
- 入力中シンタックスに問題があるところには赤いマーカーがでるよ!
- 保存する時、goフォーマッタで整形されるよ!
- パッケージ名やオブジェクト名のあとドット入力で関数やメソッドの候補が出るよ!
- アルファベットを一文字でも入力すると適切なシンボル候補出るよ!
- デバッグを開始するとgdbでできることがひと通りできるよ!
- Windows用やLinux用もあり、条件さえ揃えば同じ事が出来るはず。
- パッケージドキュメントをHTMLビューで見れる。
- パッケージ一覧や、パッケージソースもブラウズできる。
依存パッケージの一括インストール
追記:ちょっといいところに気がついたので書いてみる。
Pythonの場合、easy_installやpipなどで目的のパッケージのインストールをすれば、 依存するパッケージ一式を一緒にインストール出来ますが、 それはパッケージのメタ情報が書かれた setup.pyに必要な依存を列挙しておく事で解決します。 直接依存したパッケージ名を書いておけば、ネストされた依存も自動的に 解決を繰り返してPyPIサービスからどんどん引き込んでインストールされます。
「goの場合依存パッケージがどこに書かれるのか?」
パッケージソースコードのimport節はコンパイル時にだけ使われるのではありません。 インターネット上のパッケージリポジトリを指すパッケージ名が列挙されていれば、 go言語版のeasy_installコマンド「go get ###」を再帰的に実行して依存パッケージをすべて インストールしてくれます。 つまり、開発時に書いたコードがそのままパッケージ依存を解決するメタ情報も兼ねています。
- go:
package gosample import "github.com/yann2192/gomq" func Sample(){ // ... }
以上のようなパッケージをgithubに公開し
go get github.com/nobonobo/gosample
# これをインストールする時、"github.com/yann2192/gomq"に依存してるので、
go get github.com/yann2192/gomq
# という処理が自動で走ります。また、gomqは"github.com/alecthomas/gozmq"にも依存してるので、
go get github.com/alecthomas/gozmq
# という処理が自動で走り、libzmqの依存を解決しようとします。
さすがにCのライブラリだけは別の手段でインストールしておく必要があります。 「brew」や「port」などで入れるだけで結構スンナリ動くことが多いですよ!
感想
ライブラリについて:
内蔵のライブラリは古参言語のようにバラエティあふれるほどではないけれど、 イマドキのネットアプリ開発には「最低限これだけは欲しい」というのがひと通り揃ってる。 この標準添付の必要十分さがgolangのウリの1つだと思います。 また、コミュニティベースのパッケージが急速に充実しつつあるように思います。 DBドライバー、ORMなんかもメジャー系はひと通りそろったんじゃないかな?
言語仕様について:
例外システムを捨てたのはオモシロイ割り切り。 昨今増えてきた非同期処理の場合、 スタックが異なるところでのエラーを親元から補足できなくなって、 従来の例外システムではエラーハンドリングが難しくなっちゃった。 ー> じゃ、捨てようということに。 よーするに最近のJavaScriptは非同期処理をするようになってから try-catch構文見なくなったでしょ?そういうことなのだろう。
統合開発環境(IDE)について:
厳格な型決め言語でこそこういったシンボル補間機能はベンリになるね! PythonでIDEったってフツーのエディタ以上の支援は大してなかったしねー。 シンタックス警告やドキュメント、ソース表示なんかは初心者のころはとっても助かります。
アウトプットについて:
シングル実行ファイルを出力してくれるのは配付にとってものすごく有利。 クロスビルド環境作るのがそんなに大変じゃなさそう。 VMじゃないのに1つのソースがほとんどのプラットフォームで動く。 goコマンド自身がコンパイラでありビルドツールでもあるってのが大きい。
で?用途は?:
現状はどこでも動くコマンドラインユーティリティを作るのに向いてるんじゃないかなー。 あとはシンプルなGUIやWebアプリ。 使いドコロは薄く広くサポートしてて、開発に必要な物は最初から揃えてる印象なんだけど、 どこかの分野でディープに使おうとするとライブラリの不足感が出そうな感じ。 でも、画像処理系と暗号化、証明書周りが標準で付属なのはスバラシイと思いますー。