コンテンツにスキップ

Go/func

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go

Goのfuncキーワードは、関数を定義するために使用される予約語です。関数はGoのプログラミングにおける基本的な構成要素であり、再利用可能なコードブロックを表します。

1. 基本的な関数宣言

[編集]
func 関数名(パラメータリスト) (戻り値の型) {
    // 関数の本体(処理内容)
    return 戻り値
}
func add(x int, y int) int {
    return x + y
}

2. パラメータと戻り値のバリエーション

[編集]

同一型の複数パラメータの省略形

[編集]
func add(x, y int) int {
    return x + y
}

複数の戻り値

[編集]
// 標準的な複数戻り値
func divide(x, y float64) (float64, error) {
    if y == 0.0 {
        return 0.0, errors.New("division by zero")
    }
    return x / y, nil
}

名前付き戻り値

[編集]
// 名前付き戻り値を使用
func divide(x, y float64) (value float64, err error) {
    if y == 0.0 {
        err = errors.New("division by zero")
        // value には代入していないのでゼロ値の 0.0 となる
    } else {
        value = x / y
        // err には代入していないのでゼロ値の nil となる
    }
    return  // 空のreturnでも名前付き変数の値が返される
}

3. 型パラメータを持つ関数(ジェネリクス)

[編集]

Go 1.18から導入されたジェネリクス機能により、型パラメータを持つ関数が定義可能になりました:

通常の関数

[編集]
func Max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
// int型に限定される

ジェネリック関数

[編集]
func Max[T constraints.Ordered](a, b T) T {
    if a > b {
        return a
    }
    return b
}
// 比較可能な任意の型に対応
使用例
maxInt := Max[int](10, 20)     // 明示的に型を指定
maxFloat := Max(10.5, 20.5)    // 型推論により自動的にfloat64型と判断

4. レシーバを持つ関数(メソッド)

[編集]
func (レシーバ レシーバの型) メソッド名(パラメータリスト) 戻り値の型 {
    // メソッドの本体
}

値レシーバを使用したメソッド

[編集]
type Rectangle struct {
    width, height float64
}

func (r Rectangle) Area() float64 {
    return r.width * r.height
}
// 元の構造体は変更されない

ポインタレシーバを使用したメソッド

[編集]
func (r *Rectangle) Scale(factor float64) {
    r.width *= factor
    r.height *= factor
}
// 元の構造体が変更される

5. 型のメソッドとジェネリック型のメソッドの比較

[編集]

通常の型のメソッド

[編集]
type IntList []int

func (l IntList) Sum() int {
    total := 0
    for _, v := range l {
        total += v
    }
    return total
}
// int型のスライスにしか対応できない

ジェネリック型のメソッド

[編集]
type List[T constraints.Ordered] []T

func (l List[T]) First() (T, bool) {
    var zero T
    if len(l) == 0 {
        return zero, false
    }
    return l[0], true
}
// 様々な型のスライスに対応可能

6. 関数型と高階関数

[編集]

関数型の宣言

[編集]
type Operation func(int, int) int

関数を引数として受け取る関数

[編集]
func applyFunc(fn func(int, int) int, a, b int) int {
    return fn(a, b)
}

// 使用例
result := applyFunc(func(x, y int) int { return x + y }, 10, 20)

関数を返す関数

[編集]
func makeAdder(x int) func(int) int {
    return func(y int) int {
        return x + y
    }
}

// 使用例
add5 := makeAdder(5)
result := add5(3)  // 8

7. 無名関数とクロージャ

[編集]

単純な無名関数

[編集]
add := func(x, y int) int {
    return x + y
}
result := add(3, 4)  // 7

クロージャとして機能する無名関数

[編集]
func makeCounter() func() int {
    count := 0
    return func() int {
        count++  // 外部スコープの変数countを参照・変更
        return count
    }
}

// 使用例
counter1 := makeCounter()
fmt.Println(counter1())  // 1
fmt.Println(counter1())  // 2

8. 標準引数と可変長引数の比較

[編集]

標準的な引数リスト

[編集]
func average(a, b, c int) float64 {
    return float64(a+b+c) / 3
}
avg := average(10, 20, 30)  // 正確に3つの引数が必要

可変長引数

[編集]
func average(nums ...int) float64 {
    total := 0
    for _, num := range nums {
        total += num
    }
    return float64(total) / float64(len(nums))
}
avg1 := average(10, 20, 30)  // 3つの引数
avg2 := average(10, 20, 30, 40, 50)  // 5つの引数も可能

9. その他の特殊なパターン

[編集]

defer文との組み合わせ

[編集]
func readFile(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close()  // 関数終了時に実行される
    
    // ファイル処理...
    return nil
}

インターフェース定義でのメソッドシグネチャ

[編集]
type Writer interface {
    Write([]byte) (int, error)
}

init関数とmain関数

[編集]
// パッケージ初期化時に自動的に実行される
func init() {
    // 初期化コード
}

// プログラムのエントリーポイント
func main() {
    // メインコード
}

10. funcキーワードの特記事項

[編集]
  1. Goでは関数はファーストクラスオブジェクトです(変数に代入可能、引数や戻り値として使用可能)。
  2. 関数のオーバーロード(同名で引数の異なる複数の関数を定義すること)はサポートされていません。
  3. すべての関数に対して型パラメータを使用できるわけではなく、main関数などは型パラメータを持てません。
  4. メソッドレシーバに型パラメータを持つ型を使用可能です。
  5. 関数の型パラメータはメソッドやフィールドを持つインターフェースで制約できます。
  6. 標準ライブラリのconstraintsパッケージには、よく使われる型制約が定義されています(Ordered, Integersなど)。

Goのfuncキーワードはこのように多様な形式で使用され、特にGo 1.18以降のジェネリクス機能の追加により、より柔軟な関数とメソッドの定義が可能になりました。