Goは、Googleで作られた静的型付けのコンパイル言語です。単一のネイティブバイナリを生成し、数秒でコンパイルでき、ガベージコレクションを備え、ゴルーチン(goroutine)とチャネルによって並行処理が言語に組み込まれています。主な活躍の場はサーバーサイドのソフトウェアで、API、ネットワークサービス、そしてそれらを動かすコマンドラインツールやクラウドツールです。
以下は完全なGoプログラムです。Runを押してください。
Goのプログラムはすべて package main の func main() から始まります。:= は変数を宣言して型を推論します(ここでは文字列のスライスである []string)。range はスライスを走査し、インデックスと値を渡します。fmt と strings は標準ライブラリのパッケージです。標準ライブラリは十分に大きいので、それ以外を何もインポートしないプログラムも珍しくありません。
GoとGolang:名前について
言語の名前は Go です。「Golang」はプロジェクトの最初のWebサイトgolang.orgに由来する通称です(現在のサイトはgo.devにあります)。Webで「go」と検索すると言語以外のものばかりが出てくるため、この呼び方が使われ続けました。公式ドキュメントは「Go」と書きますが、検索ボックスにはほぼ誰もが「golang」と入力しますし、どちらも同じものを指します。「Golang」という別の製品や方言は存在しません。
Goを作ったのは誰か、なぜ作られたのか
Robert Griesemer、Rob Pike、Ken Thompsonが2007年にGoogleでGoの設計を始めました。2009年11月にオープンソースとして公開され、Go 1.0は2012年3月にリリースされました。
動機は実務的なものでした。GoogleのC++やJavaの大規模なコードベースはビルドに長い時間がかかり、依存関係のグラフは管理しにくく、マルチコアのマシンやネットワークサービスが当たり前になっていたのに、並行処理のコードを書くと間違いが起きやすかったのです。Goの設計はこうした問題に直接答えています。
- 高速なビルド。 インポートは明示的で、使っていないインポートはコンパイルエラーになり、コンパイラはヘッダーを何度も解析し直さないので、大きなプログラムでも数秒でビルドできます。
- シンプルな言語。 キーワードは少なく、ループは1つ(
for)だけ、継承も例外もありません。書く人が違ってもコードが似た形になりやすく、大きなチームでのレビューに役立ちます。 - 言語機能としての並行処理。 並行タスクの開始はキーワード1つ(
go)で済み、タスク同士はチャネルで通信できます。 - デプロイが簡単。 出力はサーバーにコピーするだけのバイナリ1つです。通常は静的リンクされます。cgoが有効な場合は
netなどのパッケージがシステムのCライブラリにリンクすることがあり、CGO_ENABLED=0でそれを無効にできます。
Go 1.0には Go 1互換性の約束 も付いてきました。Go 1.0向けに書かれたプログラムは、その後の1.xリリースでもコンパイルでき、動き続けます。実際にはツールチェーンを更新してもコードが壊れることはまれで、長く運用するサービスでGoが信頼される大きな理由になっています。
Go言語でできること
Goが最も力を発揮するのは、ネットワークと通信し、長時間動き続け、配布しやすさが求められるプログラムです。
| 分野 | 例 |
|---|---|
| Web APIとマイクロサービス | HTTPやgRPCのサービス、Webアプリやモバイルアプリのバックエンド |
| クラウドとインフラのツール | Docker、Kubernetes、Terraform、Prometheus |
| コマンドラインツール | プラットフォームごとに単一バイナリで配布する開発者向けCLI |
| ネットワーク | プロキシ、ロードバランサー、DNSサーバー |
| データパイプライン | キューを読み、レコードを変換し、データベースに書き込むワーカー |
GUIのデスクトップアプリ、モバイルアプリ、ブラウザのフロントエンド、数値計算や機械学習にはあまり向いていません。これらの分野では他のエコシステムのほうがはるかに良いライブラリを持っています。
主な特徴をコードで見る
型推論つきの静的型付け
すべての変数はコンパイル時に型が決まりますが、型を書く場面はあまりありません。:= が推論します。
Goは数値型どうしを暗黙に変換しません。count * price は一方が int、もう一方が float64 なのでコンパイルできず、float64(count) と自分で書く必要があります。これにより、気づかないうちに起きる切り捨てや精度のバグを防げます。
エラーは値
Goには例外がありません。失敗する可能性のある関数は最後の戻り値として error を返し、呼び出し側がそれをチェックします。
if err != nil のパターンは、Goのコードで最も見慣れた1行です。冗長ですが、それが狙いです。プログラムが失敗しうる場所がすべて、その場で目に見えます。エラーのラップや検査についてはエラー処理を参照してください。
ゴルーチンとチャネル
ゴルーチンは、プログラムの他の部分と並行して動く関数です。スタックは数キロバイトしか使わないので、何千個も動かすのはごく普通のことです。チャネルを使うと、ゴルーチン間で安全に値を受け渡せます。
3つのゴルーチンは並行して動くので、3行はどの順番でも出力されえます。何度か実行すると、違う順番が見られるかもしれません。main はちょうど3つの値を受信するので、終了する前にすべてを待ちます。
「implements」のないインターフェース
型は、必要なメソッドを持っているだけでインターフェースを満たします。implements キーワードはありません。
Rect も Circle も Shape に一切触れていませんが、どちらも []Shape に格納できます。そのため、具体的な型が書かれたずっと後で、それを使う側のパッケージにインターフェースを定義できます。
1つのツールチェーン
go コマンドがすべてを担います。go run はコンパイルして実行し、go build はバイナリを作り、go test はテストを実行し、go fmt はコードを整形し、go vet は怪しい書き方を検出し、go mod は依存関係を管理します。公式のフォーマットスタイルは1つだけで gofmt が強制するので、Goのプロジェクトで波かっこやインデントについて議論することはありません。
Goがあえて持たない機能
他の言語でよく見る機能のいくつかは、意図的に省かれています。
- クラスも継承もありません。 構造体、メソッド、インターフェース、埋め込みを使います。
- 例外はありません。 エラーは戻り値です。
panicはありますが、通常の失敗ではなくバグのためのものです。 - 三項演算子はありません。
if/elseを書きます。 whileキーワードはありません。 すべてのループをforで書きます。- 関数のオーバーロードもデフォルト引数もありません。
- ジェネリクスはGo 1.18からで、 C++のテンプレートやJavaのジェネリクスと比べると意図的に機能が絞られています。
率直なトレードオフ
冗長さ。 明示的なエラーチェックや、三項演算子のような省略記法がないことで、Goのコードは同じ処理のPythonやKotlinより長くなります。読むのは簡単ですが、書く行数は増えます。
ガベージコレクション。 Goのコレクタは停止時間が短いものの、ガベージコレクタであることに変わりはありません。ハードリアルタイムのシステムや、1回1回のメモリ確保が問題になるコードでは、C、C++、Rustのほうが細かく制御できます。
nil値。 Goにはnilのポインタ、マップ、スライス、インターフェースがあります。nilポインタの参照は実行時のpanicになり、Rustの型システムのようにコンパイラがそれを防いではくれません。
小さな型システム。 直和型はなく、列挙型もなく(定数と iota で組み立てます)、ジェネリクスはよくある用途はカバーしますが、高度な型レベルプログラミングはできません。
エコシステムの穴。 Webサービス、データベース、クラウドAPI向けのライブラリは非常に充実しています。GUI、科学計算、機械学習については、Python、C++、Juliaのほうがはるかに多くのライブラリを持っています。
他の言語との比較
| Go | Python | Java | Rust | |
|---|---|---|---|---|
| 型付け | 静的 | 動的 | 静的 | 静的 |
| 実行形態 | ネイティブバイナリ | インタプリタ | JVMバイトコード | ネイティブバイナリ |
| メモリ | ガベージコレクション | ガベージコレクション | ガベージコレクション | 所有権、GCなし |
| 並行処理 | ゴルーチン、チャネル | スレッド、asyncio(GILがCPU並列を制限) | スレッド、仮想スレッド | スレッド、async |
| 学習コスト | 低い | 低い | 中程度 | 高い |
Rustほどの学習コストもJavaほどの定型的な記述もなしに、コンパイル言語の性能と簡単なデプロイがほしいときにGoを選びます。
Go言語は学ぶ価値があるか
バックエンドのサービス、コマンドラインツール、クラウドインフラ関連のものを書くなら、価値があります。そのエコシステムの多くはGoで書かれていて、ソースを読むことも仕事の一部です。言語が小さいので必要な投資は控えめで、基本の構文は数日、イディオムに沿った並行処理とエラー処理は数週間の練習で身につきます。
手元でGoを書き始めるには、Goをインストールしてから、最初のプログラムを1行ずつ説明しているHello Worldのページに進んでください。
よくある質問
Go言語(Golang)は何に使われていますか?
主にバックエンドとインフラのソフトウェアです。WebサーバーやAPI、マイクロサービス、コマンドラインツール、ネットワーク関連のコード、クラウドツールなどに使われます。Docker、Kubernetes、Terraform、PrometheusはどれもGoで書かれています。デスクトップGUI、モバイルアプリ、データサイエンスで使われることはまれです。
GoとGolangは同じものですか?
同じです。言語の正式名は Go です。「Golang」は最初のWebサイトのアドレスgolang.orgに由来し、「go」という単語では検索しにくいために定着しました。どちらも同じ言語、同じツールチェーンを指します。
Go言語を作ったのは誰ですか?
Robert Griesemer、Rob Pike、Ken Thompsonの3人が2007年にGoogleで設計を始めました。2009年11月にオープンソースとして発表され、Goの互換性の約束が始まったリリースであるGo 1.0は2012年3月に公開されました。
Go言語は習得しやすいですか?
言語そのものは小さく、キーワードは25個、ループ構文は1つだけで、仕様書は半日で読める長さです。他の言語の経験があるプログラマーなら、たいてい数日で動くGoのコードを書けます。時間がかかるのはイディオムの部分で、明示的なエラー処理、インターフェース、ゴルーチンとチャネルを使った正しい並行処理がそれにあたります。
Go言語はコンパイル言語ですか、インタプリタ言語ですか?
コンパイル言語です。go build はインタプリタや仮想マシンに依存しないネイティブのマシンコードのバイナリを生成します。go run もコンパイルしており、一時的な場所にビルドしてその結果を実行しているだけです。