Go言語入門:25の例で学ぶ
Go(Golang)は Google が開発した言語です。シンプルで、コンパイルが速く、並行処理(concurrency)を標準で備えているため、サーバー、ツール、クラウドシステムで人気があります。この記事には 25 個のコード例があり、すべて Go 1.27 で実行した実際の出力を載せています。基本から、並行処理、Web ハンドラー、ジェネリクスまで順に説明します。
必要なもの
go.dev/dl から Go をインストールし、`go version` で確認します。`.go` ファイルを作り、`go run ファイル名.go` で実行します。
図解
例 1: こんにちは世界
最も簡単な Go プログラムです。すべてのプログラムは main パッケージと main 関数から始まります。
package main
import "fmt"
func main() {
fmt.Println("สวัสดี Go")
}
**実際の出力**
สวัสดี Go
例 2: 変数と定数
`:=` は宣言と代入を一度に行い、`var` は型を明示して宣言し、`const` は変わらない値に使います。
package main
import "fmt"
const schoolName = "โรงเรียนตัวอย่าง"
func main() {
name := "สมชาย"
var age int = 20
fmt.Println(schoolName, name, age)
}
**実際の出力**
โรงเรียนตัวอย่าง สมชาย 20
例 3: ゼロ値
値を指定せずに宣言した変数には、その型のゼロ値が入ります。たとえば 0、空文字列、false です。
package main
import "fmt"
func main() {
var n int
var s string
var b bool
var f float64
fmt.Printf("int=%d string=%q bool=%t float=%.1f\n", n, s, b, f)
}
**実際の出力**
int=0 string="" bool=false float=0.0
例 4: if と else
if と else if で判断します。条件を括弧で囲む必要はありません。
package main
import "fmt"
func main() {
score := 72
if score >= 80 {
fmt.Println("A")
} else if score >= 70 {
fmt.Println("B")
} else {
fmt.Println("C")
}
}
**実際の出力**
B
例 5: for ループ
Go のループは for の一種類だけです。カウント用にも while のようにも使えます。
package main
import "fmt"
func main() {
for i := 1; i <= 3; i++ {
fmt.Println("นับ", i)
}
n := 0
for n < 2 {
n++
}
fmt.Println("n =", n)
}
**実際の出力**
นับ 1
นับ 2
นับ 3
n = 2
例 6: switch
switch は複数の場合を比較します。明示しない限り次の case に落ちないため break は不要です。
package main
import "fmt"
func main() {
day := "เสาร์"
switch day {
case "เสาร์", "อาทิตย์":
fmt.Println("วันหยุด")
default:
fmt.Println("วันทำงาน")
}
}
**実際の出力**
วันหยุด
例 7: 配列とスライス
配列はサイズが固定です。スライスは append で伸び、s[a:b] で一部を切り出せます。
package main
import "fmt"
func main() {
arr := [3]int{1, 2, 3}
s := []int{10, 20}
s = append(s, 30, 40)
fmt.Println("array:", arr, "len:", len(arr))
fmt.Println("slice:", s, "len:", len(s), "cap:", cap(s) >= 4)
fmt.Println("ตัดช่วง:", s[1:3])
}
**実際の出力**
array: [1 2 3] len: 3
slice: [10 20 30 40] len: 4 cap: true
ตัดช่วง: [20 30]
例 8: マップ
マップはキーと値の組を保存します。`v, ok :=` の形式でキーの有無を確認できます。
package main
import "fmt"
func main() {
scores := map[string]int{"สมชาย": 85, "สมหญิง": 72}
scores["สมศักดิ์"] = 45
if v, ok := scores["สมชาย"]; ok {
fmt.Println("คะแนน:", v)
}
delete(scores, "สมหญิง")
fmt.Println("จำนวน:", len(scores))
}
**実際の出力**
คะแนน: 85
จำนวน: 2
例 9: 複数の戻り値を持つ関数
関数は複数の値を返せます。通常はエラーを最後の戻り値として返します。
package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("หารด้วยศูนย์ไม่ได้")
}
return a / b, nil
}
func main() {
q, err := divide(10, 2)
fmt.Println("ผล:", q, "error:", err)
_, err = divide(1, 0)
fmt.Println("error:", err)
}
**実際の出力**
ผล: 5 error: <nil>
error: หารด้วยศูนย์ไม่ได้
例 10: クロージャ
外側のスコープの変数を覚えている関数です。カウンターや非公開の状態に使えます。
package main
import "fmt"
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
next := counter()
fmt.Println(next(), next(), next())
}
**実際の出力**
1 2 3
例 11: 構造体(struct)とメソッド
struct は複数のデータをまとめ、メソッドはその型に動作を結びつけます。
package main
import "fmt"
type Student struct {
Name string
Score int
}
func (s Student) Grade() string {
if s.Score >= 80 {
return "A"
}
return "B"
}
func main() {
s := Student{Name: "สมชาย", Score: 85}
fmt.Println(s.Name, s.Grade())
}
**実際の出力**
สมชาย A
例 12: インターフェース
インターフェースは型が持つべきメソッドの集合を定めます。そのメソッドを持つ型は自動的にそのインターフェースを満たします。
package main
import "fmt"
type Shape interface {
Area() float64
}
type Rect struct{ W, H float64 }
func (r Rect) Area() float64 { return r.W * r.H }
func main() {
var s Shape = Rect{W: 3, H: 4}
fmt.Printf("พื้นที่ = %.1f\n", s.Area())
}
**実際の出力**
พื้นที่ = 12.0
例 13: ポインター
&x は変数のアドレスを返し、*p はそのアドレスの値を読み書きします。関数の呼び出し元の値を変えられます。
package main
import "fmt"
func increment(n *int) {
*n++
}
func main() {
x := 5
increment(&x)
fmt.Println("x =", x)
}
**実際の出力**
x = 6
例 14: エラーの処理
fmt.Errorf と %w でエラーを作り、errors.Is で既知のエラーと一致するか確認します。
package main
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("ไม่พบข้อมูล")
func find(id int) error {
if id != 1 {
return fmt.Errorf("รหัส %d: %w", id, ErrNotFound)
}
return nil
}
func main() {
err := find(2)
fmt.Println(err)
fmt.Println("ตรงกับ ErrNotFound:", errors.Is(err, ErrNotFound))
}
**実際の出力**
รหัส 2: ไม่พบข้อมูล
ตรงกับ ErrNotFound: true
例 15: defer
defer は関数が終わるまで呼び出しを遅らせます。ファイルを閉じるなど、後始末に向いています。
package main
import "fmt"
func main() {
defer fmt.Println("ทำงานสุดท้าย")
fmt.Println("เริ่มต้น")
fmt.Println("ประมวลผล")
}
**実際の出力**
เริ่มต้น
ประมวลผล
ทำงานสุดท้าย
例 16: panic と recover
panic は通常の処理を止めます。recover は defer された関数の中でのみ捕まえられるので、プログラム全体が落ちずに済みます。
package main
import "fmt"
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("กู้คืนจาก panic: %v", r)
}
}()
return a / b, nil
}
func main() {
fmt.Println(safeDivide(10, 2))
fmt.Println(safeDivide(1, 0))
}
**実際の出力**
5 <nil>
0 กู้คืนจาก panic: runtime error: integer divide by zero
例 17: ゴルーチン(goroutine)
go キーワードで並行に動く処理を始めます。sync.WaitGroup はすべての処理が終わるまで待ちます。
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
_ = n * n
}(i)
}
wg.Wait()
fmt.Println("ทุกงานเสร็จแล้ว")
}
**実際の出力**
ทุกงานเสร็จแล้ว
例 18: チャネル(channel)
チャネルはゴルーチン同士で値を受け渡します。この例では、ゴルーチンから main へ値を送り、最後にチャネルを閉じます。
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 1; i <= 3; i++ {
ch <- i * 10
}
close(ch)
}()
for v := range ch {
fmt.Println("ได้รับ", v)
}
}
**実際の出力**
ได้รับ 10
ได้รับ 20
ได้รับ 30
例 19: select とタイムアウト
select は複数のチャネルを同時に待ちます。time.After で待つ最大時間を決められます。
package main
import (
"fmt"
"time"
)
func main() {
result := make(chan string)
go func() {
time.Sleep(200 * time.Millisecond)
result <- "เสร็จ"
}()
select {
case msg := <-result:
fmt.Println(msg)
case <-time.After(50 * time.Millisecond):
fmt.Println("หมดเวลา")
}
}
**実際の出力**
หมดเวลา
例 20: 共有データを守る Mutex
sync.Mutex を使うと、複数のゴルーチンが同じ変数を安全に変更できます。合計は常に正しくなります。
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
var wg sync.WaitGroup
total := 0
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
total++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("รวม =", total)
}
**実際の出力**
รวม = 100
例 21: strings パッケージと rune
strings は文字列の関数を提供します。len はバイト数を数えるため、タイ語の文字数は []rune に変換して数えます。
package main
import (
"fmt"
"strings"
)
func main() {
s := "Go เขียนง่าย"
fmt.Println(strings.ToUpper("go"), strings.Contains(s, "เขียน"))
fmt.Println(strings.Split("a,b,c", ","), len("สวัสดี"))
fmt.Println([]rune("สวัสดี")[0] == 'ส')
}
**実際の出力**
GO true
[a b c] 18
true
例 22: ファイルの読み書き
os.WriteFile と os.ReadFile は、ファイル全体を一度の呼び出しで読み書きします。
package main
import (
"fmt"
"os"
)
func main() {
if err := os.WriteFile("note.txt", []byte("บันทึกจาก Go\n"), 0644); err != nil {
fmt.Println("เขียนไม่ได้:", err)
return
}
data, err := os.ReadFile("note.txt")
if err != nil {
fmt.Println("อ่านไม่ได้:", err)
return
}
fmt.Print("อ่านได้: ", string(data))
}
**実際の出力**
อ่านได้: บันทึกจาก Go
例 23: JSON
encoding/json は struct と JSON を相互に変換します。`json:"..."` のタグでフィールド名を指定します。
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Name string `json:"name"`
Score int `json:"score"`
}
func main() {
b, _ := json.Marshal(Student{Name: "สมชาย", Score: 85})
fmt.Println(string(b))
var s Student
_ = json.Unmarshal([]byte(`{"name":"สมหญิง","score":72}`), &s)
fmt.Println(s.Name, s.Score)
}
**実際の出力**
{"name":"สมชาย","score":85}
สมหญิง 72
例 24: HTTP ハンドラーのテスト
httptest を使うと、本物のサーバーを起動せずにハンドラー関数をテストできます。
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "สวัสดีจาก Go HTTP")
}
func main() {
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
hello(rec, req)
body, _ := io.ReadAll(rec.Result().Body)
fmt.Println(rec.Code, string(body))
}
**実際の出力**
200 สวัสดีจาก Go HTTP
例 25: ジェネリクス
型パラメーター T を使い、複数の型に対応する関数を書きます。インターフェースで型の条件を指定します。
package main
import "fmt"
type Number interface {
~int | ~float64
}
func Sum[T Number](values []T) T {
var total T
for _, v := range values {
total += v
}
return total
}
func main() {
fmt.Println(Sum([]int{1, 2, 3}))
fmt.Println(Sum([]float64{1.5, 2.5}))
}
**実際の出力**
6
4
次のステップ
JSON を受け取ってファイルに保存する Web サーバーを作ってみてください。その後、タイムアウトやキャンセルのために net/http と context パッケージを学びましょう。
まとめ
Go は文法がシンプルで、型はコンパイル時に検査され、エラーは値として扱います。ゴルーチンとチャネルで並行処理を行えるため、サーバーや多くのタスクを扱う処理に適しています。