関数

関数は、データ(引数)の入力、データの処理、処理結果(戻り値)の返却をするものです。 たとえば、組み込み関数lenは、データの入力、データ長の計算、データ長の返却をします。

 入力 → 処理 → 出力
(引数)      (戻り値)

関数の宣言と呼び出し

関数の宣言と呼び出し方法をパターン別に説明します。

基本

関数宣言の基本形は、次の通りです。

func 関数名(引数の宣言) 戻り値の宣言 {
    処理
    return 戻り値
}

関数呼び出しの基本形は、次の通りです。

戻り値の変数 := 関数名(引数)

では、実際のサンプルを見ていきましょう。

まずは引数と戻り値を持たない関数です。 他のプログラミング言語のようにvoidは指定しません。 また、引数と戻り値のどちらか一方だけを省略できます。

// 挨拶する関数。引数と戻り値を持たない
func sayHello() {
    fmt.Println("hello")
}
// 関数呼び出し
sayHello() // hello

次に引数と戻り値を持つ関数です。

引数には変数名と型を宣言します。複数ある場合はカンマで区切ります。

// 足し算した結果を返す
func add(x int, y int) int {
    return x + y
}
// 関数呼び出し
// 戻り値を変数に代入して使用
result := add(1, 2)
fmt.Println(result) // 3

引数に同じ型が並ぶ場合はまとめて宣言できます。

// 足し算した結果を返す
func add(x, y int) int {
    return x + y
}

可変長引数

同じ型の可変長の引数を宣言できます。 ただし、宣言できるのは引数の末尾にひとつだけです。

可変長引数の型は...型の形式で宣言します。 可変長引数は、宣言した型のスライスとして受け取ります。 たとえば、次のサンプルの可変長引数paramsint型のスライスです。

また、関数呼び出し側は可変長引数にスライスをまとめて指定できます。 その場合はスライスの変数名...の形式で指定します。

// 足し算した結果を返す
func add(params ...int) int {
    var n int
    for _, v := range params {
        n += v
    }
    return n
}
// 関数呼び出し
// 引数は何個でもOK
fmt.Println(add(1, 2, 3, 4, 5)) // 15
// スライスをまとめて引数に指定できる
s := []int{3, 3, 3}
fmt.Println(add(s...)) // 9

複数の戻り値

戻り値は複数の値を返せます。戻り値の型は括弧で括って表現します。

// 指定されたスライスの長さと容量を返す
func lenCap(slice []int) (int, int) {
    l := len(slice)
    c := cap(slice)
    return l, c
}
// 関数呼び出し
a := make([]int, 1, 3)
l, c := lenCap(a) // 1 3

名前付き戻り値

戻り値の宣言に変数名をつけることができます。 これは、戻り値に同じ型が複数並んだ際に、それぞれの戻り値が何であるかを理解する助けとなります。 returnの戻り値の指定は省略できます。

// 指定されたスライスの長さと容量を返す
func lenCap(slice []int) (l, c int) {
    // 名前付き戻り値の変数を改めて宣言する必要はない
    l = len(slice)
    c = cap(slice)
    return
}

呼び出し側で不要な戻り値はアンダースコアにすると破棄できます。

l, _ := lenCap(a) // 2つ目の戻り値は使わない

関数の型

関数を型として表現できます。 基本形はfunc(引数宣言) 戻り値宣言です。

関数は、変数や引数や戻り値として扱うことができます。

func add(x, y int) int {
    return x + y
}

func main() {
    // 関数を変数の型として宣言
    var f func(int, int) int
    // 関数を変数に代入して実行
    f = add
    fmt.Println(f(1, 2)) // 3
}

無名関数

名前のない関数を扱えます。

func main() {
    // その場で実行
    func() {
        fmt.Println("unmnamed1")
    }() // unnamed1

    // 変数に代入して実行
    f := func() {
        fmt.Println("unnamed2")
    }
    f() // unnamed2
}

クロージャ

関数の外にある変数を使用できます。

func getCounter() func() int {
    count := 0
    return func() int {
        // 関数の外にある変数countを使用
        count++
        return count
    }
}

func main() {
    counter := getCounter()
    fmt.Println(counter()) // 1
    fmt.Println(counter()) // 2
}