特集のはじめに
Goは、2009年にGoogleにより発表されたオープンソースのプログラミング言語です。C言語の開発者Ken Thompson、UTF-8の開発者Rob Pike、memcachedの開発者Brad Fitzpatrickといった名だたるエンジニアによって開発されています。
Goはシンプルな言語仕様であるため学習が比較的容易で、豊富な標準パッケージが同梱されているためすばやく目的を達成できます。また、巨大なコードでも高速にコンパイルできるため大規模開発にも適しており、Windows、OS X、Linuxなどの環境に合わせた実行ファイルを生成するクロスコンパイルのしくみがあるため作成したプログラムを容易に配布できます。並行処理のサポートも充実しており、ミドルウェアの開発などにも適しているとされています。
本特集では、2014年6月にリリースされた最新バージョンであるGo 1.3をベースに、本章でGoの特徴や環境構築、2章で基本文法、3章でGoでの型の考え方、4章で代表的な標準パッケージ、5章では並行処理のノウハウについて徹底解説します。
なお、本特集のサンプルコードは、WEB+DB PRESS Vol.82のサポートサイトから入手できます。
言語の特徴
Goは、CやC++などが使用されるシステムプログラミングの領域で、より効率良くプログラムを書くことを目的に作られました。巨大なコードベースのプロダクトを、多人数の開発者によって開発・メンテナンスするような場面で、品質を保つための工夫が随所に施されています。
以降ではGoの基本的な特徴を紹介します。
言語をシンプルに保つ
Goは、ほかの言語が持つような機能の多くを削り、言語をシンプルに保っています。こうした機能の排除は、コンパイルの高速化や、予期せぬミスを減らすことに役立っています。
最小限の構文
Goでは、繰り返し構文はfor文しかなく、while文やdo/while文などはサポートされていません。また条件分岐でも、ifの波括弧は省略できず、三項演算子もありません。こうした表現方法を制限することで、開発者による表現のばらつきを抑えることができます。
また、マクロのようなプリプロセスが必要な構文もサポートされていません。Goは巨大なコードベースも高速にコンパイルできるようにするため、コンパイルを遅くする原因となるこうした構文は極力取り込まない方針を採っています。
危険の回避
メモリリークの原因となりやすいポインタ演算や、意図せぬエラーの原因になる暗黙の型変換などは排除されています。
また、宣言されたものの使われていない変数や、インポートされたものの使われていないパッケージなどがコードに存在すると、コンパイルすら通りません。巨大なコードベースでは、コードを追加することよりもコードを削除するほうが、影響範囲が読みにくく難しいことがあります。そこでGoは不要なコードの存在をコンパイル時に検出することで、不要なコードが存在することを防いでいます。
例外の排除
RubyやJavaなど例外をサポートする言語では、関数呼び出しをtry/catch構文などで囲み、内部で発生した異常を例外として捕捉しますが、Goでは関数が多値を返せることを利用して、発生した異常を戻り値として呼び出し側に返す方針を採ります。また、ゼロ除算や配列の範囲外の添字へのアクセスなどでは、パニックとリカバという異常を処理するしくみを別途備えています。詳しくは2章で解説します。
特徴的な機能
Goは言語をシンプルに保つ一方で、近年のプログラミングに求められるモダンな機能は積極的にサポートしています。
クロスコンパイルのサポート
Goは、コンパイル時にOSとCPUアーキテクチャを指定し、その環境に合わせた実行ファイルを生成できます。詳細は本章のコラムで解説します。
並行処理のサポート
Goでは、ゴルーチンという軽量スレッドを用いて処理を並行に実施し、同時に実行されているゴルーチンの間ではチャネルという機能でデータをやりとりするしくみが備わっています。詳細は5章で解説します。
充実した開発環境
Goでは開発を助けるさまざまなパッケージやツールが最初から用意されており、さらに各エディタやツールのためのプラグインなども公開されているため、すぐに開発を始めることができます。
標準パッケージ
Goは標準パッケージが充実しており、外部のパッケージに頼らずともかなりの開発をカバーできます(表1)。
標準パッケージの一覧は公式ドキュメントから確認できます。
表1 Goの主な標準パッケージ
パッケージ | 用途 |
archive、compress | tar、zlibなどの圧縮やアーカイブ形式のサポート |
crypto | AES、RSAなどの暗号化形式のサポート |
database | RDBへのSQLクエリインタフェースとドライバインタフェース |
encoding | JSON、XML、CSVなどのフォーマットのサポート |
go | Go言語自体のパーサやAST(抽象構文木)の取得 |
html、text | HTMLやTEXT形式のテンプレート |
net | TCP、HTTP、RPC、SMTPなどのネットワークプログラミングのサポート |
sync | 並行処理のためのロックや同期化のサポート |
testing | テストやベンチマークのサポート |
ツールのサポート
Goには開発を支援するコマンドが同梱されており、さまざまなツールを使用できます(表2)。
コマンドの解説は公式ドキュメントから確認できます。
表2 Goの主なコマンドラインツール
コマンド | 用途 |
go build | プログラムのビルド |
go fmt | Goの規約に合わせてプログラムを整形 |
go get | 外部パッケージの取得 |
go install | プログラムのビルドとインストール |
go run | プログラムのビルドと実行 |
go test | テストやベンチマークの実行 |
go tool yacc | パーサをGoで出力するGo実装のyacc(パーサジェネレータ) |
godoc | ソースからドキュメントの生成 |
各エディタのサポート
Goでは、有志による主要なエディタやツールへのプラグインも公開されています[1]。公開されているエディタやプラグインはGoのWikiにまとめられています。
採用事例
GoのWikiには、Goが採用されたプロジェクトの一部が掲載されています。最近はDevOps界隈での採用が目立ちますが、並行性を活かしたミドルウェアの開発や、クロスコンパイルによる配布容易性を活かしたコマンドラインツールなどにも採用されています(表3)。
インストール
Goは、公式に配布されている各環境に合わせたインストーラを用いて簡単にインストールできます。インストーラはダウンロードページから入手できます。お使いの環境に合わせてダウンロードし、実行してください。
インストールが完了したら、コマンドラインから次のコマンドを実行し、バージョンが出力されれば成功です。
hello world
まずはhello worldを作成して実行してみましょう。
作成
次の内容でhello.goというファイルを作成してください。文法については2章で解説するので、本章ではわからずとも問題ありません。
実行
作成したプログラムをすぐに実行したい場合は、次のようにgo run
コマンドを使用します。
hello world
が出力されれば成功です。
コンパイル
次にこのプログラムをコンパイルして、できあがったファイルを実行してみます。コンパイルには、go build
コマンドを使用します。
hello.goをコンパイルすると、hello(Windowsの場合はhello.exe)という実行形式のバイナリファイルが生成されます。ここでは64ビットのOS Xを用いてコンパイルしたため、生成された実行ファイルは、同じ64ビットのOS XであればGoがインストールされていなくても実行できます。
フォーマット
Goでは、標準のコーディング規約が定められています。これにより、プロジェクトごとにコーディング規約を用意したり、開発者同士の嗜好(しこう)を巡って無駄な言い争いが起こることを防いでいます。たとえばGoでは、ソフトタブ(半角スペース)ではなくハードタブ(タブ文字)でインデントすることや、半角スペースを入れるべき場所/入れるべきでない場所などを規約として定めています。
このコーディング規約はわざわざ覚える必要はありません。go fmt
コマンドを用いると、規約に従ってコードを自動で整形できます。
開発の際は、エディタでの保存時やバージョン管理システムへのコミット時などにgo fmt
が実行されるようにし、常にフォーマット済みな状態にすることを心がけましょう。
ドキュメント
標準パッケージやサードパーティパッケージのドキュメントを確認するには、godoc
コマンドを使用します。たとえばhello.goで使用したfmtパッケージのドキュメントが見たければ、次のように実行します。
ブラウザから見る公式サイトと同様のインタフェースでドキュメントを確認したい場合は、-http
オプションを付けて実行します。
サーバが起動し、http://localhost:3000/
にアクセスするとドキュメントを見ることができます。
Goのプロジェクト構成とパッケージ
先ほどは1つのファイルにプログラムを記述しましたが、ファイルが増えたときは、パッケージを分割する場合があります。その場合は、プロジェクトをきちんと構成し環境変数を指定する必要があります。
ここでは、myprojectというプロジェクトの中でgosampleというパッケージを作成し、そのパッケージをmainパッケージから呼び出すよう構成してみます。
ディレクトリの作成
まず、myprojectディレクトリを起点に、次のようにbin、pkg、srcという3つのディレクトリを作成します。
環境変数GOPATHの指定
次に、myprojectディレクトリのパスをGOPATH
という環境変数に指定します。
Goのコマンドは、このGOPATH
とその下にある先の3つのディレクトリの命名規則を用いて、Makefileなどの構成ファイルは一切なしで、依存関係を解決してビルドできるようになっています。
パッケージの作成
そしてパッケージを作ります。Goでは、1つのパッケージは1つのディレクトリに格納します。
gosampleパッケージ
まずgosampleパッケージを作ります。src/gosample/gosample.go
を次のように作成します。
上記ではgosampleパッケージの中に、Messageという変数を定義しています。
mainパッケージ
次にmainパッケージを作ります。src/main/main.go
を次のように作成します。
上記ではmain パッケージのmain()
の中で、gosample パッケージを使用しています。このgosampleパッケージのインポートは、先ほど指定したGOPATH
から、$GOPATH/src/gosample
と解決され実行されます。
ビルドと実行
実行
正しくGOPATH
が設定された状態でgo run
コマンドでmain.goを実行すると、gosampleパッケージの場所が正しく解決され、プログラムを実行できます。
ビルド
次にこのプログラムをビルドして、1つの実行形式のファイルを生成してみます。go build
コマンドを用いてその場に実行ファイルを作ることもできますが、go install
コマンドを用いると、生成されたファイルが$GOPATH/bin
に自動的に格納されます。
ビルドしたあとのプロジェクト内は次のようになります。
このようにbinディレクトリに実行ファイルが生成されるため、次のように$GOPATH/bin
をパスに追加しておけば、go install
したコマンドに常にパスを通すことができます。
パッケージの公開
作成したパッケージを公開してみましょう。といってもGo には、Ruby のRubyGems やNode.js のnpm(Node Package Manager)のような標準のパッケージ管理システムはありません。代わりに、GitやMercurialでリポジトリが公開されていれば使用できます。専用の設定ファイルなども必要ありません。
先ほどのgosampleパッケージをGitHubで公開してみます。まずは空のリポジトリでよいので自分のGitHubにリポジトリを用意してください。ここではhttps://github.com/wdpress/gosample
にリポジトリを作成し、公開することにします。リポジトリのURLやディレクトリ名は、自分で作成したものに置き換えてください。
ディレクトリ構造の修正
このリポジトリに合わせてディレクトリ構造を修正します。
mainパッケージの修正
パッケージを使うmain.goも修正します。
GitHubに公開
あとは、gosampleディレクトリ以下をGitで管理し、GitHubにpushするだけです。
これで公開が完了です。
公開したパッケージを使ってみる
では、試しに自分で取得して使ってみましょう。
ローカルにあるパッケージを削除し、GitHubから取得します。取得にはgo get
コマンドを使います。
取得したパッケージは、go get
で指定したパスと同じディレクトリ構成でプロジェクト内に展開されます。
再度main.goをビルドして実行し、正しく動作すれば成功です。
GOPATHを固定する
複数のプロジェクトがマシン内の別の個所にある場合は、プロジェクトを移動するたびにGOPATH
を指定しなおす必要があります。その面倒を避けるため最近では、マシン内に1ヵ所だけGOPATH
を指定し、すべてのパッケージをそこで管理し、開発もそこで行う方法が主流になってきました。これからGoを始める場合は、まずこの方法を試してみることをお勧めします。
まとめ
本章では、Goの特徴と環境構築方法について解説しました。いよいよ次章以降では、Goでのプログラミングについてより細かく解説していきます。