Go

#12
TIOBE#7
PYPL#12
GitHub#20
RedMonk#12
IEEESpectrum#8
JetBrains#11
プログラミング言語システムプログラミング並行処理マイクロサービスクラウドDevOps

プログラミング言語

Go

概要

Goは、Googleが開発したシンプルで高性能なプログラミング言語です。

詳細

Goは2009年にGoogleのRobert Griesemer、Rob Pike、Ken Thompsonによって開発されたオープンソースのプログラミング言語です。シンプルで読みやすい構文、高速なコンパイル、優れた並行処理機能を特徴としています。ガベージコレクションを持ちながらも高性能を実現し、大規模なシステム開発に適しています。マイクロサービス、クラウドアプリケーション、DevOpsツールの開発で特に人気があり、Docker、Kubernetes、Prometheusなどの重要なツールがGoで書かれています。

書き方の例

Hello World

package main

import "fmt"

// 基本的な出力
func main() {
    fmt.Println("Hello, World!")
    
    // 変数を使った出力
    message := "こんにちは、Go!"
    fmt.Println(message)
    
    // フォーマット文字列を使った出力
    name := "太郎"
    age := 25
    fmt.Printf("私の名前は%sで、%d歳です。\n", name, age)
}

変数と型

package main

import "fmt"

func main() {
    // 基本的な型
    var name string = "太郎"
    var age int = 25
    var height float64 = 175.5
    var isActive bool = true
    
    // 短縮形での変数宣言
    city := "東京"
    temperature := 22.5
    
    // 複数変数の同時宣言
    var (
        firstName string = "田中"
        lastName  string = "太郎"
        score     int    = 85
    )
    
    // 定数
    const Pi = 3.14159
    const MaxUsers = 100
    
    fmt.Printf("名前: %s, 年齢: %d, 身長: %.1fcm\n", name, age, height)
    fmt.Printf("都市: %s, 気温: %.1f度\n", city, temperature)
    fmt.Printf("フルネーム: %s %s, スコア: %d\n", firstName, lastName, score)
    fmt.Printf("円周率: %g, 最大ユーザー数: %d\n", Pi, MaxUsers)
}

配列、スライス、マップ

package main

import "fmt"

func main() {
    // 配列(固定長)
    var numbers [5]int = [5]int{1, 2, 3, 4, 5}
    fruits := [3]string{"りんご", "バナナ", "オレンジ"}
    
    // スライス(可変長)
    colors := []string{"赤", "青", "緑"}
    colors = append(colors, "黄色") // 要素の追加
    
    // make関数でスライス作成
    scores := make([]int, 3, 5) // 長さ3, 容量5
    scores[0] = 85
    scores[1] = 92
    scores[2] = 78
    
    // マップ(辞書)
    person := map[string]interface{}{
        "name": "田中太郎",
        "age":  30,
        "city": "東京",
    }
    
    // make関数でマップ作成
    grades := make(map[string]int)
    grades["数学"] = 85
    grades["英語"] = 92
    grades["国語"] = 78
    
    fmt.Printf("配列: %v\n", numbers)
    fmt.Printf("果物: %v\n", fruits)
    fmt.Printf("色: %v\n", colors)
    fmt.Printf("スコア: %v\n", scores)
    fmt.Printf("人: %v\n", person)
    fmt.Printf("成績: %v\n", grades)
}

関数

package main

import "fmt"

// 基本的な関数
func add(a, b int) int {
    return a + b
}

// 複数の戻り値
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("ゼロで除算はできません")
    }
    return a / b, nil
}

// 名前付き戻り値
func rectangle(width, height float64) (area, perimeter float64) {
    area = width * height
    perimeter = 2 * (width + height)
    return // 名前付き戻り値は自動的に返される
}

// 可変長引数
func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}

// 高階関数(関数を引数に取る)
func applyOperation(a, b int, operation func(int, int) int) int {
    return operation(a, b)
}

func main() {
    // 関数の呼び出し
    result := add(10, 5)
    fmt.Printf("10 + 5 = %d\n", result)
    
    // 複数戻り値の処理
    quotient, err := divide(10, 3)
    if err != nil {
        fmt.Printf("エラー: %v\n", err)
    } else {
        fmt.Printf("10 ÷ 3 = %.2f\n", quotient)
    }
    
    // 名前付き戻り値
    area, perimeter := rectangle(5, 3)
    fmt.Printf("長方形 - 面積: %.1f, 周囲: %.1f\n", area, perimeter)
    
    // 可変長引数
    total := sum(1, 2, 3, 4, 5)
    fmt.Printf("合計: %d\n", total)
    
    // 高階関数
    multiply := func(x, y int) int { return x * y }
    product := applyOperation(4, 6, multiply)
    fmt.Printf("4 × 6 = %d\n", product)
}

構造体とメソッド

package main

import "fmt"

// 構造体の定義
type Person struct {
    Name string
    Age  int
    City string
}

// メソッドの定義(レシーバー付き関数)
func (p Person) GetInfo() string {
    return fmt.Sprintf("%s(%d歳、%s在住)", p.Name, p.Age, p.City)
}

// ポインタレシーバー(構造体を変更する場合)
func (p *Person) SetAge(newAge int) {
    p.Age = newAge
}

// 埋め込み(継承のような機能)
type Employee struct {
    Person   // Personを埋め込み
    JobTitle string
    Salary   int
}

func (e Employee) GetJobInfo() string {
    return fmt.Sprintf("%s - 職種: %s, 給与: %d円", e.GetInfo(), e.JobTitle, e.Salary)
}

func main() {
    // 構造体のインスタンス作成
    person1 := Person{
        Name: "田中太郎",
        Age:  25,
        City: "東京",
    }
    
    // フィールドへのアクセス
    fmt.Println("名前:", person1.Name)
    fmt.Println("年齢:", person1.Age)
    
    // メソッドの呼び出し
    fmt.Println(person1.GetInfo())
    
    // ポインタレシーバーメソッドの呼び出し
    person1.SetAge(26)
    fmt.Println("更新後:", person1.GetInfo())
    
    // 埋め込み構造体
    employee := Employee{
        Person: Person{
            Name: "山田花子",
            Age:  30,
            City: "大阪",
        },
        JobTitle: "エンジニア",
        Salary:   5000000,
    }
    
    fmt.Println(employee.GetJobInfo())
}

インターフェース

package main

import "fmt"

// インターフェースの定義
type Shape interface {
    Area() float64
    Perimeter() float64
}

// 長方形の構造体
type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

// 円の構造体
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14159 * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * 3.14159 * c.Radius
}

// インターフェースを受け取る関数
func printShapeInfo(s Shape) {
    fmt.Printf("面積: %.2f, 周囲: %.2f\n", s.Area(), s.Perimeter())
}

func main() {
    rectangle := Rectangle{Width: 5, Height: 3}
    circle := Circle{Radius: 2}
    
    // 同じインターフェースとして扱う
    printShapeInfo(rectangle)
    printShapeInfo(circle)
    
    // インターフェーススライス
    shapes := []Shape{rectangle, circle}
    for i, shape := range shapes {
        fmt.Printf("図形%d: ", i+1)
        printShapeInfo(shape)
    }
}

Goroutine(並行処理)

package main

import (
    "fmt"
    "sync"
    "time"
)

// 基本的なgoroutine
func sayHello(name string) {
    for i := 0; i < 3; i++ {
        fmt.Printf("Hello %s! (%d)\n", name, i+1)
        time.Sleep(100 * time.Millisecond)
    }
}

// WaitGroupを使った同期
func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 関数終了時にDone()を呼ぶ
    
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    // 基本的なgoroutine
    go sayHello("Alice")
    go sayHello("Bob")
    
    // メインgoroutineで少し待機
    time.Sleep(400 * time.Millisecond)
    fmt.Println("---")
    
    // WaitGroupを使った同期処理
    var wg sync.WaitGroup
    
    for i := 1; i <= 3; i++ {
        wg.Add(1) // カウンターを増やす
        go worker(i, &wg)
    }
    
    wg.Wait() // すべてのgoroutineが完了するまで待機
    fmt.Println("All workers completed")
}

チャネル(並行処理での通信)

package main

import (
    "fmt"
    "time"
)

// 基本的なチャネル
func sender(ch chan string) {
    messages := []string{"Hello", "Go", "Channels"}
    for _, msg := range messages {
        ch <- msg // チャネルに送信
        time.Sleep(100 * time.Millisecond)
    }
    close(ch) // チャネルを閉じる
}

// バッファ付きチャネル
func bufferedChannelExample() {
    ch := make(chan int, 3) // バッファサイズ3
    
    // 非同期でデータを送信
    go func() {
        for i := 1; i <= 5; i++ {
            ch <- i
            fmt.Printf("Sent: %d\n", i)
        }
        close(ch)
    }()
    
    // データを受信
    for value := range ch {
        fmt.Printf("Received: %d\n", value)
        time.Sleep(200 * time.Millisecond)
    }
}

// selectを使った複数チャネルの制御
func selectExample() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(100 * time.Millisecond)
        ch1 <- "Channel 1"
    }()
    
    go func() {
        time.Sleep(200 * time.Millisecond)
        ch2 <- "Channel 2"
    }()
    
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-ch1:
            fmt.Println("From ch1:", msg1)
        case msg2 := <-ch2:
            fmt.Println("From ch2:", msg2)
        case <-time.After(300 * time.Millisecond):
            fmt.Println("Timeout")
        }
    }
}

func main() {
    fmt.Println("=== 基本的なチャネル ===")
    ch := make(chan string)
    go sender(ch)
    
    for message := range ch {
        fmt.Println("Received:", message)
    }
    
    fmt.Println("\n=== バッファ付きチャネル ===")
    bufferedChannelExample()
    
    fmt.Println("\n=== Select文 ===")
    selectExample()
}

エラーハンドリング

package main

import (
    "errors"
    "fmt"
    "os"
)

// カスタムエラー型
type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("Validation error in %s: %s", e.Field, e.Message)
}

// エラーを返す関数
func validateAge(age int) error {
    if age < 0 {
        return ValidationError{
            Field:   "age",
            Message: "年齢は0以上である必要があります",
        }
    }
    if age > 150 {
        return ValidationError{
            Field:   "age",
            Message: "年齢は150以下である必要があります",
        }
    }
    return nil
}

// ファイル操作でのエラーハンドリング
func readFile(filename string) (string, error) {
    content, err := os.ReadFile(filename)
    if err != nil {
        return "", fmt.Errorf("ファイル読み込みエラー: %w", err)
    }
    return string(content), nil
}

// panicとrecover
func riskyFunction() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Panic回復: %v\n", r)
        }
    }()
    
    fmt.Println("危険な処理を実行中...")
    panic("何かがうまくいかなかった!")
    fmt.Println("この行は実行されません")
}

func main() {
    // エラーハンドリングの例
    ages := []int{25, -5, 200, 30}
    
    for _, age := range ages {
        if err := validateAge(age); err != nil {
            fmt.Printf("エラー - 年齢 %d: %v\n", age, err)
            
            // 型アサーションでカスタムエラーかチェック
            if ve, ok := err.(ValidationError); ok {
                fmt.Printf("  フィールド: %s\n", ve.Field)
            }
        } else {
            fmt.Printf("年齢 %d は有効です\n", age)
        }
    }
    
    // ファイル読み込みエラーの例
    _, err := readFile("nonexistent.txt")
    if err != nil {
        fmt.Printf("ファイルエラー: %v\n", err)
    }
    
    // panic/recoverの例
    fmt.Println("\n=== Panic/Recover ===")
    riskyFunction()
    fmt.Println("メイン処理は継続されます")
}

バージョン

バージョン リリース日 主な新機能
Go 1.23 2024-08 Range-over-func, Timer reset behavior
Go 1.22 2024-02 For-range over integers, Math/rand v2
Go 1.21 2023-08 Built-in functions min/max/clear, WASM
Go 1.20 2023-02 Comparable types, Context improvements
Go 1.19 2022-08 Generics improvements, Doc comments
Go 1.18 2022-03 Generics, Fuzzing, Workspaces
Go 1.17 2021-08 Module graph pruning, Call stack traces

参考ページ

公式ドキュメント

学習リソース

開発ツール