Go言語入門|シンプルで高速なプログラミング言語の基本と始め方

kento_morota 12分で読めます

Go言語(Golang)は、Googleが2009年に公開したプログラミング言語です。シンプルな構文、高速なコンパイル、組み込みの並行処理機能を特徴とし、バックエンド開発やクラウドインフラの分野で広く採用されています。Docker、Kubernetes、Terraformなど、モダンなインフラツールの多くがGoで書かれています。

本記事では、Go言語の特徴から環境構築、基本文法、並行処理、Webサーバーの構築まで、入門に必要な知識を実践的に解説します。

Go言語の特徴と他言語との違い

Go言語がなぜ多くのプロジェクトで選ばれているのか、その特徴を理解しましょう。

シンプルさへの徹底

Goの設計思想は「シンプルさ」です。予約語は25個しかなく、C言語やJavaと比較して構文が格段にシンプルです。クラスの継承、ジェネリクスの複雑な型パラメータ(Go 1.18で導入されたジェネリクスはシンプルに設計されています)、例外処理のtry-catchなど、他の言語にある複雑な機能をあえて排除しています。

この設計により、チームの全員が同じスタイルでコードを書き、他人のコードを短時間で理解できるようになります。大規模チームでの開発に特に適しています。

コンパイルの高速性

GoはC/C++のようなコンパイル言語ですが、コンパイルが非常に高速です。数十万行規模のプロジェクトでも数秒でコンパイルが完了します。さらに、単一のバイナリファイルに静的リンクでコンパイルされるため、デプロイが極めてシンプルです。依存するランタイムやライブラリを別途インストールする必要がありません。

並行処理のネイティブサポート

Goは言語レベルで並行処理をサポートしています。goroutineとchannelという2つのプリミティブにより、複雑なマルチスレッドプログラミングをシンプルに記述できます。数千〜数万のgoroutineを同時に実行しても、メモリ消費はごくわずかです。

充実した標準ライブラリ

HTTPサーバー、JSON処理、暗号化、テスト、プロファイリングなど、多くの機能が標準ライブラリとして提供されています。外部ライブラリへの依存を最小限に抑えられるのが大きな利点です。

環境構築と最初のプログラム

Go言語の開発環境を構築し、最初のプログラムを実行してみましょう。

Goのインストール

公式サイト(https://go.dev/dl/)からインストーラーをダウンロードできます。macOSではHomebrewを使ってbrew install goでもインストール可能です。Linuxでは公式のtarファイルを展開し、PATHを設定します。

インストール後、ターミナルでgo versionを実行してバージョン情報が表示されれば成功です。

プロジェクトの初期化

Goのプロジェクトはgo modで管理します。プロジェクトのディレクトリを作成し、go mod init プロジェクト名で初期化します。これによりgo.modファイルが生成され、依存関係が管理されるようになります。

Hello Worldの作成

main.goファイルを作成し、以下のような構造でコードを書きます。package mainでメインパッケージを宣言し、import "fmt"で標準ライブラリのfmtパッケージをインポートし、func main()にエントリーポイントの処理を記述します。fmt.Println("Hello, World!")で文字列を出力します。

go run main.goで実行、go buildでコンパイルしてバイナリを生成します。

基本文法:変数・型・制御構文

Go言語の基本的な文法を確認しましょう。他の言語の経験があれば、すぐに慣れるはずです。

変数宣言と型

Goは静的型付け言語です。変数の宣言にはvarキーワードを使うか、短縮宣言:=を使います。

var name string = "Go"のように明示的に型を指定できますが、name := "Go"と書けば型推論が働きます。関数内では短縮宣言が一般的です。

基本型として、int、float64、string、bool、byteなどがあります。Goではゼロ値(Zero Value)の概念が重要で、変数を初期化しなくても型に応じたデフォルト値(数値は0、文字列は""、boolはfalse)が設定されます。

関数

Goの関数はfuncキーワードで宣言します。特徴的なのは、複数の戻り値を返せることです。

Goでは慣習的に、エラーを戻り値の最後の要素として返します。result, err := someFunction()のように受け取り、if err != nilでエラーを確認するパターンが至るところで使われます。これがGoのエラーハンドリングの基本形です。

制御構文

if文
Goのif文は条件式に括弧が不要です。また、条件式の前に短い文を書ける独自の構文があります。if err := doSomething(); err != nil { ... }のように、処理の実行とエラーチェックを1行で書けます。

for文
Goにはforだけがループ構文です。whileやdo-whileはありません。通常のカウンタベースのループ、条件だけのループ(while相当)、rangeを使ったイテレーションの3形式を使い分けます。

switch文
Goのswitchは自動的にbreakするため、フォールスルーしません(フォールスルーさせたい場合は明示的にfallthroughを記述します)。

構造体とインターフェース

Goにはクラスがありません。代わりに構造体(struct)とインターフェース(interface)を使ってデータの構造と振る舞いを定義します。

構造体(struct)

構造体は、関連するフィールドをまとめたデータ型です。type User struct { Name string; Age int }のように定義し、フィールドにアクセスします。

構造体にメソッドを定義するには、レシーバーを使います。func (u User) Greet() string { return "Hello, " + u.Name }のように、関数名の前にレシーバーを記述します。これにより、構造体に振る舞いを持たせられます。

値レシーバー(u User)はレシーバーのコピーに対して操作し、ポインタレシーバー(u *User)は元の構造体を直接操作します。フィールドを変更する必要がある場合はポインタレシーバーを使いましょう。

インターフェース(interface)

Goのインターフェースは暗黙的に実装されます。「このインターフェースを実装します」と明示する必要がなく、インターフェースが要求するメソッドを持っていれば自動的に実装したとみなされます。

たとえば、type Writer interface { Write(data []byte) error }というインターフェースがあれば、Writeメソッドを持つ任意の構造体がWriter型として使えます。

この暗黙的実装により、既存の型に後からインターフェースを適用することが容易です。テスト時のモック作成も簡単になり、テスタブルなコードが書きやすくなっています。

goroutineとchannelによる並行処理

Go言語の最大の強みの1つが、シンプルな並行処理です。goroutineとchannelの使い方を理解しましょう。

goroutine

goroutineは、Go独自の軽量スレッドです。関数呼び出しの前にgoキーワードを付けるだけで、その関数を非同期に実行できます。OSスレッドとは異なり、goroutineの初期スタックサイズはわずか数KBで、数万のgoroutineを同時に実行しても問題ありません。

Goのランタイムスケジューラが、goroutineを利用可能なOSスレッドに自動的にマッピングするため、開発者はスレッド管理を意識する必要がありません。

channel

channelは、goroutine間でデータを安全にやり取りするための仕組みです。ch := make(chan int)でチャンネルを作成し、ch <- valueで送信、value := <-chで受信します。

チャンネルは同期の仕組みも兼ねています。バッファなしのチャンネルでは、送信側は受信側が準備できるまでブロックし、受信側は送信されるまでブロックします。これにより、goroutine間の同期をシンプルに実現できます。

バッファ付きチャンネルmake(chan int, 10)を使えば、バッファが一杯になるまでブロックせずに送信できます。

select文

select文は、複数のチャンネル操作を同時に待ち受ける構文です。switch文に似ていますが、チャンネルの送受信に対して動作します。タイムアウトの実装やキャンセル処理に活用できます。

並行処理のパターン

Fan-out/Fan-in
1つのチャンネルから複数のgoroutineに処理を分散(Fan-out)し、各goroutineの結果を1つのチャンネルに集約(Fan-in)するパターンです。CPUバウンドな処理の並列化に有効です。

Worker Pool
固定数のgoroutine(ワーカー)がジョブキューからタスクを取り出して処理するパターンです。goroutineの数を制御したい場合に使います。

Context
contextパッケージは、goroutineのキャンセルやタイムアウトを管理するための標準的な仕組みです。HTTPリクエストのタイムアウト、処理のキャンセル伝播に不可欠で、Goプログラミングでは必須の知識です。

実践:簡単なWebサーバーの構築

Go言語の学習として、標準ライブラリだけでWebサーバーを構築してみましょう。外部フレームワークなしでも実用的なHTTPサーバーが構築できるのがGoの強みです。

基本的なHTTPサーバー

Goのnet/httpパッケージを使えば、数行でHTTPサーバーを起動できます。http.HandleFuncでルーティングを定義し、http.ListenAndServe(":8080", nil)でサーバーを起動します。

ハンドラ関数はfunc(w http.ResponseWriter, r *http.Request)のシグネチャを持ちます。ResponseWriterでレスポンスを書き込み、Requestからリクエスト情報を取得します。

JSONレスポンスの返却

APIサーバーではJSON形式のレスポンスが一般的です。Goのencoding/jsonパッケージを使い、構造体をJSONにシリアライズします。構造体のフィールドにバッククォートでjson:"field_name"タグを付けることで、JSONのキー名を制御できます。

json.NewEncoder(w).Encode(data)でレスポンスにJSONを書き込みます。Content-Typeヘッダをapplication/jsonに設定することを忘れないようにしましょう。

ミドルウェアの実装

ミドルウェアは、HTTPハンドラの前後に処理を挟む仕組みです。Goでは関数をラップすることで実装します。ロギング、認証、CORS設定など、共通処理をミドルウェアとして実装することで、コードの再利用性が向上します。

ミドルウェアの関数シグネチャはfunc(next http.Handler) http.Handlerが一般的です。元のハンドラを受け取り、前後に処理を追加した新しいハンドラを返します。

Go言語の開発ツールとエコシステム

Go言語には強力な開発ツールが揃っています。

標準ツール

gofmt
コードフォーマッターです。Goではコードのフォーマットが公式に統一されており、gofmtで自動整形します。フォーマットに関する議論が不要になるため、チーム開発の効率が上がります。

go vet
コードの潜在的な問題を検出する静的解析ツールです。Printf系関数のフォーマット文字列の不一致、到達不能コードなどを検出します。

go test
テストランナーです。_test.goファイルにテストを記述し、go test ./...で全テストを実行します。ベンチマークテストやカバレッジ測定も標準でサポートされています。

主要なサードパーティツールとフレームワーク

Gin / Echo
高性能なWebフレームワークです。標準ライブラリのnet/httpだけでも十分ですが、ルーティング、バリデーション、ミドルウェア管理などの機能が豊富に必要な場合はこれらのフレームワークが便利です。

GORM
Go用のORMライブラリです。データベース操作を構造体ベースで行えます。マイグレーション、アソシエーション、トランザクション管理などの機能を提供します。

golangci-lint
複数のリンターを統合して実行するツールです。CI/CDパイプラインに組み込むことで、コード品質を自動的にチェックできます。

まとめ

Go言語は、シンプルな構文、高速なコンパイル、組み込みの並行処理機能を備えた実用的なプログラミング言語です。goroutineとchannelによる並行処理はGoの最大の強みであり、Webサーバーやマイクロサービスの開発で特に威力を発揮します。

標準ライブラリが充実しており、外部依存を最小限に抑えた開発が可能です。gofmtによるコードフォーマットの統一、明示的なエラーハンドリング、シンプルなインターフェースの仕組みにより、チーム開発での生産性が高い言語です。

まずはHello Worldから始め、基本文法を習得したら、goroutineとchannelによる並行処理を試してみてください。標準ライブラリだけで実用的なWebサーバーを構築する体験は、Goの力強さを実感する最良の方法です。

#Go#Golang#プログラミング
共有:
無料メルマガ

週1回、最新の技術記事をお届け

AI・クラウド・開発の最新記事を毎週月曜にメールでお届けします。登録は無料、いつでも解除できます。

プライバシーポリシーに基づき管理します

起業準備に役立つ情報、もっとありますよ。

まずは話だけ聞いてもらう