Go言語開発メモ
Goインストール
最新バージョンは https://go.dev/dl/ で確認してからダウンロードします。以下のコマンドは 2026年6月時点での最新バージョン(go1.26.4)を例として示しています。
# 最新バージョンを https://go.dev/dl/ で確認してからダウンロード
wget https://go.dev/dl/go1.26.4.linux-amd64.tar.gz
既存の Go を削除してから展開します(上書きは破損の恐れがあるため必ず削除してから行う)。
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.26.4.linux-amd64.tar.gz
PATH に追加します(~/.bashrc または ~/.profile に追記)。
export PATH=$PATH:/usr/local/go/bin
export PATH=$PATH:$(go env GOPATH)/bin
source ~/.bashrc
インストールが完了したら、バージョンを確認します。
go version
参考にしたページ
初期設定のベストプラクティス
Go 1.11 以降は go.mod によるモジュール管理が標準となり、GOPATH の役割が変化しました。
GOPATH の現在の役割
~/go/bin/:go installしたツールのバイナリ置き場~/go/pkg/mod/: モジュールキャッシュ
go env -w で設定する(推奨)
環境変数は go env -w コマンドで設定ファイルに永続保存するのが推奨です。
シェルの設定ファイルに直接書く必要はありません。
# 設定ファイルの場所を確認
go env GOENV
# モジュールプロキシ(デフォルト:proxy.golang.org)
go env -w GOPROXY=https://proxy.golang.org,direct
# 社内プライベートリポジトリの設定
go env -w GOPRIVATE=gitlab.mycompany.com,github.com/my-org
# 設定を削除
go env -u GOPROXY
主な環境変数
| 変数 | デフォルト | 説明 |
|---|---|---|
GOPROXY |
https://proxy.golang.org,direct | モジュール取得先プロキシ |
GOPRIVATE |
(未設定) | プロキシ・チェックサムDBをバイパスするパターン |
GOSUMDB |
sum.golang.org | モジュールの改ざん検証DB |
GOBIN |
$GOPATH/bin | go install バイナリの出力先 |
プロキシとチェックサムDB
proxy.golang.org: モジュールのミラーキャッシュ。go get 時に VCS から直接取得する代わりに利用sum.golang.org: Merkle ツリーでモジュールのハッシュを管理する透過性ログ。改ざんを検証goproxy.io: proxy.golang.org にアクセスしにくい環境向けの代替公開プロキシ
Go の特徴的な機能
goroutine と channel
goroutine は初期スタック約 2KB の軽量スレッドで、数万〜数百万単位で起動できます。
channel で goroutine 間の通信を行い、select 文で複数 channel を同時に待機できます。
package main
import "fmt"
func sum(s []int, c chan int) {
total := 0
for _, v := range s {
total += v
}
c <- total
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c
fmt.Println(x, y, x+y)
}
interface(構造的型付け)
Go の interface は構造的型付けを採用しており、implements キーワードは不要です。
メソッドを持っていれば自動的に interface を実装していると見なされます。
type Animal interface {
Sound() string
Name() string
}
type Dog struct{}
func (d Dog) Sound() string { return "Woof" }
func (d Dog) Name() string { return "Dog" }
// implements キーワード不要。メソッドを持っていれば自動的に実装扱い
func Describe(a Animal) {
fmt.Printf("%s says %s\n", a.Name(), a.Sound())
}
defer / panic / recover
// defer: 関数終了時に必ず実行(LIFO 順)
func readFile(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close() // 忘れずに閉じる
// ...
return nil
}
// panic / recover: 例外的なエラー処理
func safeDiv(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered: %v", r)
}
}()
return a / b, nil
}
error handling
Go のエラーは戻り値として返します。Go 1.13 以降は %w でエラーをラップできます。
var ErrNotFound = errors.New("not found")
// エラーのラップ(Go 1.13+)
func findUser(id int) (*User, error) {
user, err := db.Find(id)
if err != nil {
return nil, fmt.Errorf("findUser(%d): %w", id, err)
}
return user, nil
}
// エラーの検査
if errors.Is(err, ErrNotFound) { /* センチネルエラーとの一致 */ }
var ve *ValidationError
if errors.As(err, &ve) { /* エラーチェーン内の型を取り出す */ }
generics(Go 1.18+)
func Min[T constraints.Ordered](x, y T) T {
if x < y {
return x
}
return y
}
fmt.Println(Min(3, 5)) // 3
fmt.Println(Min("a", "b")) // a
ゼロ値
変数宣言のみで型に応じたゼロ値が自動的に代入されます。
int は 0、bool は false、string は ""、
ポインタ・スライス・マップ・チャネルは nil です。
複数戻り値
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
result, err := divide(10, 3)
Goプロジェクトの作成
プロジェクトディレクトリを作成します。
mkdir -p $GOPATH/github.com/naughty-ghost/hello
プロジェクトディレクトリに移動します。
cd $GOPATH/github.com/naughty-ghost/hello
main.goファイルを作成します。
touch main.go
main.goファイルに以下のコードを記述します。
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
main.goファイルをビルドします。
go build
実行ファイルが生成されます。
./hello
以下のように表示されれば、プロジェクトの作成は完了です。
Hello, World!
Go モジュール
Goモジュールを初期化します。
go mod init github.com/naughty-ghost/hello
hogeモジュールを追加する場合は、以下のようになります。
go install github.com/naughty-ghost/hoge
go.modの未使用の Go モジュールを削除する、かつコード上で使用されているが go.mod に追加されていない Go モジュールを追加します。
go mod tidy
Go テスト
テストファイルを作成します。
touch main_test.go
main_test.goファイルに以下のコードを記述します。
package main
import "testing"
func TestHello(t *testing.T) {
got := Hello()
want := "Hello, World!"
if got != want {
t.Errorf("got %q want %q", got, want)
}
}
テストを実行します。
go test
以下のように表示されれば、テストは成功です。
ok github.com/naughty-ghost/hello 0.001s
命名規則
Go言語の命名規則は以下の通りです。
- ファイル名: スネークケース。(例)hello_world.go
- ディレクトリ名: 小文字。1単語が望ましい。複数の単語がある場合はケバブケース。
- パッケージ名: 小文字。1単語が望ましい。複数の単語がある場合はスネークケース。(例)http time など。
- 関数名: 外部に公開する場合は先頭を大文字にするというGo言語のルールがあるのでそれに合わせて、アッパーキャメルケースかローワーキャメルケースを使い分ける。
- 構造体名: 外部に公開する場合は先頭を大文字にするというGo言語のルールがあるのでそれに合わせて、アッパーキャメルケースかローワーキャメルケースを使い分ける。
- 変数名: 短い変数名が推奨されますが、変数のスコープが広い場合は長い変数名を使うこともあります。変数名はローワーキャメルケースを使います。
参考にしたページ
Go + Docker でマルチステージビルドを使用する
マルチステージビルドを使用すると、ビルド時に必要なファイルをコピーするだけで、 実行時には不要なファイルを含めないことができる。 以下のように、マルチステージビルドを使用する。
FROM golang:1.22 AS build
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o app main.go
FROM alpine
COPY --from=build /app/app /app/
WORKDIR /app
CMD ["./app"]
Go + Docker でscratchイメージを使用するときの注意
cgoを無効化する
cgoが有効なままビルドすると、scratchイメージで実行できない。 ビルド時にcgoを無効化するためには、CGO_ENABLED=0を環境変数に設定する。
CGO_ENABLED=0 go build -o app main.go
ルートCA証明書をコピーする
ルートCA証明書をコピーしないと、Dockerイメージ内でSSL通信ができない。 ルートCA証明書を別のイメージからコピーすることができる。今回は、golang:1.22の/etc/ssl/certs/ca-certificates.crtを使用する。 Dockerfileに以下を追加する。
FROM golang:1.22 AS build
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o app main.go
FROM scratch
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # 証明書のコピー
COPY --from=build /app/app /app/
WORKDIR /app
CMD ["./app"]
scratchイメージのタイムゾーンを設定する
scratchイメージにはタイムゾーンが設定されていない。 以下のように、タイムゾーンを設定する。
FROM scratch
COPY --from=golang:1.22 /usr/share/zoneinfo /usr/share/zoneinfo
ENV TZ=Asia/Tokyo
もしくはソースコードのmainパッケージでtime/tzdataをインポートする。
import _ "time/tzdata"
Dockerイメージのサイズを小さくする
scratchイメージを使用すると、Dockerイメージのサイズを小さくすることができる。 以下のように、scratchをベースイメージに指定する。
FROM scratch
Go + PostgreSQL
id に自動生成のUUIDを設定する
"github.com/gofrs/uuid"
"gorm.io/driver/postgres"
"gorm.io/gorm"
パッケージを使用して、idに自動生成のUUIDを設定する。
Id uuid.UUID `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"`
マイグレーション時にuuid_generate_v4が存在しないエラーが発生したら次のSQLを実行する。
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
更新履歴
- 新規作成。
- 更新。
- インストールのベストプラクティス・初期設定・Go の特徴的な機能を追加。