---
title: "Go言語とは｜1.27系の導入からHTTP APIを動かすまでの実装入門"
url: "https://www.issoh.co.jp/tech/details/17483/"
published: 2026-09-08
updated: 2026-10-20
categories: ["Go"]
publisher: "株式会社一創"
---

# Go言語とは｜1.27系の導入からHTTP APIを動かすまでの実装入門

Go言語の日本語入門記事は「シンプルで速い」「並行処理が得意」で終わるものが多く、その説明だけでは手元で何かが動くところまで届きません。しかも上位に並ぶ解説の多くは2022年前後の記述で、ジェネリクスもJSONの扱いも当時の前提のままです。この記事は、2026年8月19日公開の1.27系を実機に入れるところから、Hello World、goroutineとchannel、標準ライブラリだけで書くHTTP APIまでを一本のコードでつなぎます。バージョン番号と仕様の記述は2026年9月8日時点の公式ドキュメントから取りました。

## まとめ｜Go言語を選ぶ前に決める3点と1.27系で標準に入った機能

先に結論です。着手前に決めるのは、①どの版で書くか、②フレームワークを入れるか標準ライブラリだけで済ませるか、③並行処理をgoroutineで自分で組むか既存の枠組みに乗るか。この3つが決まれば、あとは書く作業に落ちます。

版は1.27系です。[公式のリリース履歴](https://go.dev/doc/devel/release)によると go1.27.0 が2026年8月19日、修正版の go1.27.1 が2026年9月1日に出ています。導入時にバージョンで悩む必要はありません。`GOTOOLCHAIN`の既定値が`auto`のため、プロジェクトの`go.mod`が要求する版へgoコマンド自身が切り替わります。

1.27で入った変更のうち、入門の段階から効くものが3つあります。メソッドが自前の型パラメータを宣言できるジェネリックメソッド、標準に加わった`encoding/json/v2`と`uuid`、そして正式化された`goroutineleak`プロファイルです。外部ライブラリを入れずに済む範囲が広がったので、入門で書くコードの依存は`go.mod`1ファイルと標準ライブラリだけで足ります。

## Go言語の成り立ちと言語仕様の小ささを公式仕様書の記述から確かめる

GoはGoogleで2007年に設計が始まり、2009年にオープンソースとして公開された言語です。C++の大規模ビルドの遅さと、動的言語の実行性能という二つの不満から出発しているため、設計の判断がほぼ全て「コンパイルと実行を速く保つ」側に倒れています。

この設計思想が最も分かりやすく出ているのが仕様書の分量です。[言語仕様書](https://go.dev/ref/spec)で予約されているキーワードは25語しかなく、1ページに収まります。継承がなく、クラスもなく、例外もない。他言語から来ると機能が足りないように見えますが、書き方の分岐が減るぶん他人のコードを読む速度が上がります。標準の書式整形コマンド`gofmt`がスタイル議論そのものを消すのも同じ発想です。

書き方の指針は[Effective Go](https://go.dev/doc/effective%5Fgo)という公式文書に集約されています。命名、エラーの返し方、インターフェースの切り方まで公式が言い切っているので、チームでコーディング規約を一から作る手間が要りません。受託開発で要員が入れ替わる前提の案件では、この「議論の余地の少なさ」がそのまま引き継ぎコストの低さになります。

## Go 1.27.1をインストールしてgo versionで確認するまでの手順

導入は[公式のインストール手順](https://go.dev/doc/install)のとおりで、パッケージマネージャを使わない方法が最も確実です。ディストリビューション同梱のGoは版が古いことが多く、後述のツールチェーン切り替えとも噛み合いません。

### LinuxとmacOSとWindowsそれぞれの導入コマンドと確認する手順

Linuxは公式アーカイブを展開する方式です。既存のディレクトリを消してから展開するところまでが公式の指示で、上書き展開は古いファイルが残るため避けます。

```
# Linux: 既存を消してから展開する
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.27.1.linux-amd64.tar.gz

# PATH を通す（$HOME/.profile などに追記）
export PATH=$PATH:/usr/local/go/bin
export PATH="$PATH:$(go env GOPATH)/bin"

# 導入確認
go version
```

macOSはpkgインストーラ、Windowsはmsiインストーラを実行するだけでPATHまで設定されます。どのOSでも確認方法は同じで、新しいターミナルを開いて`go version`を実行し`go1.27.1`が返れば完了です。2行目の`GOPATH/bin`へのPATH追加は、`go install`で入れたコマンドを直接叩くために要ります。ここを飛ばすと、後からツールを入れたときに「コマンドが見つからない」で足止めされます。

### GOTOOLCHAINが既定のautoでバージョンを自動的に切り替える仕組み

Goには、インストールした版と実際に使う版を分ける仕組みがあります。[公式ドキュメント](https://go.dev/doc/toolchain)によると`GOTOOLCHAIN`の既定値は`auto`で、これは`local+auto`の短縮形です。手元に入れた版で始め、必要なら別の版を取りに行きます。

```
# go.mod の2行が切り替えを決める
go 1.27.0
toolchain go1.27.1

# 常に手元の版だけを使う（切り替えを止める）
GOTOOLCHAIN=local go build ./...

# 既定版を固定しつつ必要時のみ上げる
go env -w GOTOOLCHAIN=go1.27.1+auto
```

`go`行はそのモジュールが要求する最小版、`toolchain`行は推奨する版です。`go get`で入れた依存がより新しい版を要求すると、goコマンドが該当版をダウンロードして実行し、`go.mod`の記述も書き換えます。CIで版を固定したい場合だけ`GOTOOLCHAIN=local`を明示してください。動きの詳細は[GOTOOLCHAINとは｜Go Toolchainでバージョンを自動切り替えする仕組みと設定方法](https://www.issoh.co.jp/tech/details/5635/)で追えます。

## go mod initからHello Worldをビルドして配布物を作るまでの流れ

Goのプロジェクトはモジュール単位です。[公式チュートリアル](https://go.dev/doc/tutorial/getting-started)の手順は3コマンドで終わり、雛形生成ツールもIDEも要りません。

### go mod initでモジュールを初期化して最初のパッケージを書く作業

空のディレクトリで`go mod init`を実行すると`go.mod`が1つできます。引数はモジュールパスで、公開するなら取得元のURLと同じ文字列、社内利用なら任意の識別子で構いません。

```
mkdir hello && cd hello
go mod init example.com/hello

cat > main.go <<'EOF'
package main

import "fmt"

func main() {
	fmt.Println("こんにちは、Go")
}
EOF

go run .
```

`package main`と`func main()`の組み合わせが実行可能プログラムの条件です。外部パッケージを使う場合は`go get`で追加し、`go mod tidy`で未使用の依存を落とします。[依存管理の公式解説](https://go.dev/doc/modules/managing-dependencies)にあるとおり、依存の実体は`go.sum`のハッシュで固定されるため、ロックファイルを別に持つ必要はありません。1.27からは`go mod tidy`が重複した`require`ブロックを自動でまとめます。

### go runとgo buildの違いとクロスコンパイルで配布物を作る指定方法

`go run`は一時ディレクトリでビルドして即実行し、成果物を残しません。手元の確認用です。配布するものを作るのは`go build`で、出てくるのは実行に必要なものを含んだ単一のバイナリになります。ランタイムや依存ライブラリを配布先に入れる作業が要らない、というのがGoの運用面での最大の利点です。

```
# 手元の環境向けにビルド
go build -o bin/hello .

# Linux/amd64 向けにクロスコンパイル
GOOS=linux GOARCH=amd64 go build -o bin/hello-linux .

# Windows/arm64 向け
GOOS=windows GOARCH=arm64 go build -o bin/hello.exe .

# ビルド情報を埋め込む
go build -ldflags "-X main.version=1.0.0" -o bin/hello .
```

環境変数を2つ指定するだけで別OS向けの実行ファイルが作れます。CIでLinux向けバイナリを作ってコンテナに載せる流れがそのまま組めるので、Dockerイメージは実行ファイル1つを置くだけの小さなものになります。Kubernetesやコンテナ周辺のツールにGoで書かれたものが多いのも、この性質による。

## goroutineとchannelで並行処理を書いて手元で動かして確かめる

Goを選ぶ理由の大半がここです。並行処理が言語機能として組み込まれており、スレッドプールの設計をライブラリ選定から始める必要がありません。

### goroutineを起動してWaitGroupで待ち合わせる最小のコード

関数呼び出しの前に`go`を書くだけで、その関数は別の実行単位として走ります。数KB程度のスタックから始まり、必要に応じて伸びるため、数万個を同時に立てても破綻しません。終了を待つには`sync.WaitGroup`を使います。

```
package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	results := make([]int, 5)

	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func(n int) {
			defer wg.Done()
			results[n] = n * n
		}(i)
	}

	wg.Wait()
	fmt.Println(results)
}
```

`defer wg.Done()`は関数を抜けるときに必ず実行されます。異常終了の経路でも待ち合わせが解除されるので、この書き方が定型です。仕組みの詳細は[ゴルーチン（Goroutine）とは？Go言語の並行処理を支える軽量スレッドの仕組みと使い方](https://www.issoh.co.jp/tech/details/4632/)に整理しています。

### channelで結果を集約してcontextでタイムアウトを与える書き方

共有変数をロックで守る代わりに、値をchannel経由で渡すのがGoの流儀です。下は3件の処理を並行で走らせ、2秒で打ち切る形になります。

```
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

ch := make(chan string, 3)
for _, url := range urls {
	go func(u string) {
		ch <- fetch(ctx, u)
	}(url)
}

for i := 0; i < 3; i++ {
	select {
	case s := <-ch:
		fmt.Println(s)
	case <-ctx.Done():
		fmt.Println("打ち切り:", ctx.Err())
		return
	}
}
```

`select`は複数のchannelを同時に待ち、先に準備できたほうを処理します。`ctx.Done()`を並べておけば、期限切れやキャンセルで抜ける経路が同じ構文で書けます。channelの容量指定や閉じ方は[Go言語のChannelとは？その特徴と用途について徹底解説](https://www.issoh.co.jp/tech/details/5061/)、contextの使い分けは[Go言語のcontext入門｜BackgroundとTODOの使い分け、キャンセルとタイムアウトの実装](https://www.issoh.co.jp/tech/details/3405/)を参照してください。

## 標準ライブラリだけでJSONを返すHTTP APIサーバを実装して起動する

Goの標準ライブラリはWebサーバを含みます。外部フレームワークなしでルーティングもJSONも書けるため、最初の1本は素のまま作るのが理解を早めます。

### ルーティングとJSON応答を実装して起動を確認するまでのコード

[net/httpパッケージ](https://pkg.go.dev/net/http)の`ServeMux`は、メソッドとパスの変数を含むパターンを受け付けます。`GET /items/{id}`のように書き、値は`r.PathValue("id")`で取り出します。

```
package main

import (
	"encoding/json"
	"net/http"
)

type item struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /items/{id}", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(item{ID: r.PathValue("id"), Name: "サンプル"})
	})
	http.ListenAndServe(":8080", mux)
}
```

構造体のタグでJSONのキー名を指定します。起動して`curl localhost:8080/items/42`を叩けば応答が返ります。ここまで外部依存はゼロです。ミドルウェアやバインディングを厚く使いたくなった段階でフレームワークを検討することになり、その比較は[Go Echoフレームワーク実践ガイド｜特徴・Gin比較とベストプラクティス](https://www.issoh.co.jp/tech/details/3399/)にまとめています。

### 処理中のリクエストを取りこぼさずにサーバを停止させる終了処理

`ListenAndServe`のまま本番に出すと、デプロイのたびに処理中のリクエストが切れます。`http.Server`を自分で組み立て、`Shutdown`で終了させる形にしてください。

```
srv := &http.Server{Addr: ":8080", Handler: mux}

go func() {
	if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
		log.Fatal(err)
	}
}()

sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
	log.Println("強制終了:", err)
}
```

`Shutdown`は新規接続の受け付けを止め、処理中のリクエストが終わるのを待ってから戻ります。渡した`context`の期限が来ると待つのをやめるので、上の例では最大10秒待つ挙動です。コンテナ運用ではSIGTERMを受けてから停止までの猶予が決まっているため、その値より短い期限を設定します。

## 他言語の経験者がGoのエラー処理と型の扱いでつまずく箇所を先に潰す

文法が小さいぶん、他言語の書き方をそのまま持ち込むと詰まる箇所が集中します。事前に2点だけ押さえておけば、書き始めの手戻りはほぼ消えます。

### 例外がない前提でerrorを返す書き方とラップして返す判断基準

Goに`try/catch`はありません。失敗しうる関数は戻り値の最後に`error`を返し、呼び出し側が毎回確認します。冗長に見えますが、どの行で失敗しうるかがコード上に必ず現れるという性質と引き換えです。

```
f, err := os.Open(path)
if err != nil {
	return fmt.Errorf("設定の読み込みに失敗: %w", err)
}
defer f.Close()

// 呼び出し側で原因を判定する
if errors.Is(err, os.ErrNotExist) {
	// ファイルが無い場合の分岐
}
```

判断基準は単純です。呼び出し元が原因で分岐する可能性があるなら`%w`でラップして原因を残し、ログに出して終わるだけなら文字列にして返します。`panic`を使うのは、プログラムの前提が崩れて続行に意味がない場合に限ります。判定関数の使い分けは[Go言語のエラーハンドリング実装ガイド｜errors.Is/As/AsTypeとpanic recoverの使い分け](https://www.issoh.co.jp/tech/details/3895/)で詳しく扱いました。

### ジェネリクスとinterfaceで型を抽象化するときの使い分けの基準

Goには継承がありません。抽象化の手段はinterfaceとジェネリクスの2つで、役割が違います。interfaceは「この操作ができるもの」を表し、実装側に宣言を書かずに満たせます。ジェネリクスは「型が違うだけで処理が同じもの」をまとめる道具です。

使い分けは、処理の中身が型ごとに変わるならinterface、変わらないならジェネリクスです。1.27ではメソッド自身が型パラメータを宣言できるようになり、`math/rand/v2`の`N`のような書き方が標準側でも使われ始めました。ただし入門段階では出番が少なく、まずinterfaceを小さく切る書き方に慣れるほうが読めるコードになります。Effective Goが勧めるとおり、interfaceは実装側ではなく使う側で定義してください。

## Go 1.27で標準に入った新パッケージのうち実務に効く3つを実測で見る

ここが日本語の入門記事と最も差が出る部分です。[1.27のリリースノート](https://go.dev/doc/go1.27)には、外部ライブラリを外せる変更が並んでいます。

### JSON v2とUUIDが標準に入ったことで減らせる外部依存の範囲

`encoding/json/v2`と、その下位層の`encoding/json/jsontext`が加わりました。v2は既定の挙動が厳しくなっており、不正なUTF-8と重複キーを拒否します。v1互換のオプションが用意されているので、既存コードを一斉に書き換える必要はありません。アンマーシャルの性能も改善されています。

あわせて`uuid`パッケージが標準入りしました。これまでUUIDの生成に外部ライブラリを入れていた案件では、依存を1本減らせます。受託開発の実務では、依存が減ることはライセンス確認と脆弱性追跡の対象が減ることと同義で、保守の見積りに直接効きます。

### ジェネリックメソッドとgoroutineリーク検出が実装に与える影響

言語側の変更として、メソッドが独自の型パラメータを宣言できるようになりました。これまでジェネリクスは関数と型にしか書けず、型パラメータ付きのメソッドを持たせたい設計は回避策が必要でしたが、その制約が外れています。ただしinterfaceのメソッドでは型パラメータを宣言できません。

運用面で効くのは`goroutineleak`プロファイルの正式化です。`runtime/pprof`と`net/http/pprof`の`/debug/pprof/goroutineleak`から取得でき、channelの受け手が消えて永久に待つgoroutineを検出できます。並行処理を自分で組む言語である以上リークは付いて回るので、本番運用の初期から見る先が標準で用意された意味は小さくありません。版ごとの差分は[Go 1.27の新機能・変更点まとめ｜最新バージョンの確認方法と移行ガイド](https://www.issoh.co.jp/tech/details/10416/)で追えます。

## Go言語を採用してよい案件と見送るべき案件の条件を実務目線で言い切る

言語の善し悪しではなく、案件の条件で決まります。判断材料を条件の形で出しておきます。

### 採用してよい3つの条件と受託開発でGoを選んだときに得られる利点

採用してよいのは3条件のいずれかが当てはまる場合です。第一に、同時接続を多く捌くAPIやバッチが中心の案件。goroutineとchannelで並行処理を素直に書けて、メモリ使用量も読めます。第二に、コンテナやサーバーレスで動かす前提の案件。単一バイナリになるためイメージが小さく、起動が速い。第三に、要員の入れ替わりが想定される長期保守の案件です。文法の分岐が少なく`gofmt`で書式が揃うため、読み手の負担が版を跨いでも増えません。

3条件がそろう典型が、既存システムと外部SaaSをつなぐAPIの新規構築です。接続方式の検討や既存システム側の改修を含めて相談したい場合は[API開発・システム連携](https://www.issoh.co.jp/service/system/api/)で対応しています。

### Goを見送るべき2つの場面と判断に迷ったときに使う切り分けの材料

見送るのは2つです。1つ目は、機械学習やデータ分析が処理の中心にある案件。ライブラリの層の厚さでPythonに遠く及ばず、周辺を書くためだけにGoを選ぶ理由がありません。2つ目は、管理画面のような画面数の多い業務システムを短期で作る案件です。テンプレートとフォーム処理を一から書くことになり、この領域が厚いフレームワークを持つ言語のほうが記述量は半分以下で終わります。

迷うのは、APIと画面が半々の案件です。切り分けの基準は同時実行の要件に置いてください。秒間の処理数や外部API呼び出しの並行度が要件に書かれているならGo、書かれていないなら開発速度が出る言語を選ぶ。「速いから」だけで選ぶと、画面側の実装量で速度の利得を使い切ります。判断がつかない段階では、負荷が集中する処理だけをGoで切り出し、残りは既存の言語に置く構成も取れます。

## よくある質問

Go言語の導入検討で実際に多い質問に、公式ドキュメントの記述に沿って回答します。

### Go言語とGolangは何が違うのですか？

同じものです。正式名称はGoですが、検索で一般名詞と混ざるため、公式サイトのドメイン名でもある「golang」が通称として定着しました。公式ドキュメントの表記はGoで統一されています。求人票や技術書では両方の表記が混在しますが、指すものに違いはありません。

### Go言語の学習にはどのくらいの期間が必要ですか？

Hello WorldからHTTP APIまでなら、他言語の経験がある人で数日です。キーワードが25語しかなく、公式チュートリアルが3コマンドで終わるため入口は早い。時間がかかるのはその先で、channelの閉じ方、contextの伝播、interfaceの切り方、エラーのラップ方針の4つが実務の詰まりどころになります。

### Go言語は今から学んでも需要がありますか？

コンテナ基盤とクラウド周辺の主要ソフトウェアがGoで書かれているため、その領域の需要は続いています。1.27でも標準ライブラリの追加とランタイムの改善が入り、開発は止まっていません。ただし用途は偏っており、サーバーサイドとCLIツールが中心です。フロントエンドやデータ分析を主戦場にするなら別の言語を先に選ぶことになります。

### Go言語とPythonやJavaはどう使い分けますか？

並行処理と実行性能が要件に出ているならGo、機械学習やデータ処理が中心ならPython、既存の業務システムとエンタープライズ向けの枠組みに乗るならJavaという分け方が実務の目安です。Goは単一バイナリで配布でき、実行環境の準備が要らない点でも運用の手数が違います。

### Go言語で作ったプログラムはどうやって配布しますか？

`go build`で出た実行ファイルを置くだけです。ランタイムのインストールが不要なので、コンテナイメージには実行ファイルと証明書程度しか入りません。`GOOS`と`GOARCH`を指定すれば、開発機と違うOS・CPU向けのバイナリも同じコマンドで作れます。

## 関連記事

- [Go 1.27の新機能・変更点まとめ｜最新バージョンの確認方法と移行ガイド](https://www.issoh.co.jp/tech/details/10416/)：1.27系の変更点を個別に追う場合。
- [GOTOOLCHAINとは｜Go Toolchainでバージョンを自動切り替えする仕組みと設定方法](https://www.issoh.co.jp/tech/details/5635/)：版の固定と自動切り替えの設定。
- [ゴルーチン（Goroutine）とは？Go言語の並行処理を支える軽量スレッドの仕組みと使い方](https://www.issoh.co.jp/tech/details/4632/)：並行処理の仕組みを深く知る段階で。
- [Go言語のChannelとは？その特徴と用途について徹底解説](https://www.issoh.co.jp/tech/details/5061/)：channelの容量指定と閉じ方の実装。
- [Go言語のcontext入門｜BackgroundとTODOの使い分け、キャンセルとタイムアウトの実装](https://www.issoh.co.jp/tech/details/3405/)：キャンセル伝播を実装する段階で。
- [Go言語のエラーハンドリング実装ガイド｜errors.Is/As/AsTypeとpanic recoverの使い分け](https://www.issoh.co.jp/tech/details/3895/)：エラー設計を固める段階で。
- [Go Echoフレームワーク実践ガイド｜特徴・Gin比較とベストプラクティス](https://www.issoh.co.jp/tech/details/3399/)：標準ライブラリで足りなくなった段階で。

---

出典: [Go言語とは｜1.27系の導入からHTTP APIを動かすまでの実装入門](<https://www.issoh.co.jp/tech/details/17483/>)（株式会社一創）
