Go言語_関数

関数の記述方法

基本形

Go言語では、関数を以下の形式で定義します。

戻り値の型を引数の後ろに記述する特徴があります。


func 関数名(引数) 戻り値の型 {
  return 戻り値
}

関数名とプライベート関数

関数名が小文字から始まる場合はその関数は他のパッケージから使用できません。

つまり、プライベート関数になります。


関数名が大文字から始まる場合はその関数は他のパッケージから呼び出すことができます。

os.Exit()などのように、パッケージ関数が大文字で始まる理由はこのためです。


複数の戻り値

Go言語の関数は「多値返却」が可能です。


package main

import (
    "fmt"
)

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

func sub(x, y int) int {
    return x - y
}

func addAndSub(x, y int) (int, int) {
    return x + y, x - y
}

func main() {
    a := add(300, 200)
    b := sub(300, 200)
    c, d := addAndSub(300, 200)
    fmt.Printf("a=%d, b=%d, c=%d, d=%d\n", a, b, c, d)
}

多値返却は、特にエラー処理をするためによく使われます。


package main

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

func division(x, y int) (int, error) {
	if y == 0 {
		return 0, errors.New("Invalid number")
	}
	return x / y, nil
}

func main() {
	ans, err := division(90, 20)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println(ans)
}

なお、Go言語では宣言した変数を使わないとコンパイルエラーになります。

そのため、多値返却で利用しない値を返却する場合、アンダースコアで受け取る必要があります。


// エラーを無視する場合
ans, _ := division(12, 0)
fmt.Println(ans)

可変引数

Go言語の可変引数指定は「...」を記述します。

可変長引数は暗黙的に値を配列にコピーして関数全体のスライスに渡されます。


package main

import (
	"fmt"
)

func print_msg(messages ...string) {
    fmt.Printf("messages length = %d\n", len(messages))
    for index, msg := range messages{
        fmt.Printf("messages[%d] = %s\n", index, msg)
    }
}

func main() {
	print_msg("The", "Go", "Programming", "Language")
}

関数値

Go言語の関数はファーストクラスであり、関数は型を持ちます。

つまり、関数を変数に代入したり、関数の引数や戻り値に関数を指定できるということです。


package main

import (
	"fmt"
)

func addition(num1 int, num2 int) int {
	return num1 + num2
}

// 戻り値に関数を返す関数です
func subtraction() func(int, int) int {
	return func(num1 int, num2 int) int { return num1 - num2 }
}

func multiplication(num1 int, num2 int) int {
	return num1 * num2
}

func division(num1 int, num2 int) int {
	if num2 == 0 {
		return 0
	}
	return num1 / num2
}

// 第三引数は演算用関数を指定する。
func calcByMethod(num1 int, num2 int, method func(int, int) int) int {
	return method(num1, num2)
}

func main() {
	// 関数を変数に代入する。
	add := addition
	ans1 := add(20, 5) // 25

	// 関数の戻り値から関数を取得する。
	sub := subtraction()
	ans2 := sub(20, 5) // 15

	// 引数に関数を指定する。
	ans3 := calcByMethod(20, 5, multiplication) // 100
	ans4 := calcByMethod(20, 5, division)       // 4

	fmt.Printf("%d, %d, %d, %d\n", ans1, ans2, ans3, ans4)
}

無名関数

無名関数を変数に格納して、その変数を経由して無名関数を実行することができます。


package main

import (
	"fmt"
)

func main() {
	addTag := func(str string) string { return "<" + str + ">" }
	tag := addTag("class-view")
	fmt.Printf("%s\n", tag)
}

クロージャ

Goの関数は クロージャ(closure)です。

クロージャとは、その関数が定義された環境への参照を持った関数という意味です。

例えば、1から10までの数字を全て足す処理は以下のように記述できます。


package main

import "fmt"

func addSum() func(int) (int, int) {
	sum := 0 // 合計値を格納する変数
	return func(num int) (int, int) {
		sum = sum + num
		return num, sum
	}
}

func main() {
	calc := addSum()

	for i := 1; i <= 10; i++ {
		addVal, sumVal := calc(i)
		fmt.Printf("add value: %d -> sum: %d\n", addVal, sumVal)
	}
}

sum変数はクロージャに属する変数として利用されます。

クロージャで束縛された変数領域は、クロージャが参照され続ける限りは破棄されることがありません。

そのため、前回までの合計値をsum変数に保持することができています。

上記プログラムの実行結果は以下の通りです。


add value: 1 -> sum: 1
add value: 2 -> sum: 3
...
add value: 9 -> sum: 45
add value: 10 -> sum: 55


関連ページ