Golang 関数の戻り値とは
関数は任意の数の戻り値を持つことができ、Golangはこの機能を内部でサポートしています。
Golangにおいて関数が、複数の戻り値を返す時の基本的な書き方は以下の通りです。
func 関数名(引数1 引数1の型, 引数2 引数2の型, ...) (戻り値1の型, 戻り値2の型, ...) {
// 関数の処理
}
戻り値の型を宣言(定義)する方法
戻り値の型と値は、複数の方法で宣言することができます。
複数の型の値を返す場合は、以下のように宣言することができます。
package main
import (
"fmt"
)
func doubleInt(i int) int {
return i * 2
}
func main() {
fmt.Println(doubleInt(15)) // 30
}
同じ戻り値の型を宣言(定義)する方法
もし同じ型の戻り値を使う場合、以下のように記述してコードを短くすることができます。
package main
import (
"fmt"
)
func test(i int) (int, int) {
return i / 2, i * 2
}
func main() {
x, y := test(24)
fmt.Println(x) // 12
fmt.Println(y) // 48
}
異なる戻り値の型を宣言(定義)する方法
もし異なる型の戻り値を使用する場合は、以下のように記述します。
package main
import (
"fmt"
)
func test(i int) (int, float64) {
return i / 2, float64(i) * 2.05
}
func main() {
x, y := test(24)
fmt.Println(x) // 12
fmt.Println(y) // 49.199999999999996
}
名前付き戻り値とは
名前付き戻り値とは、戻り値の名前を定義できるGolangの機能です。
名前付き戻り値を使うメリットは、returnする値をそれぞれ明示的に書かなくて済むことです。そのため、複数の値を何段階にも分けて計算するような複雑な計算をする場合に非常に便利です。
以下は、名前付き戻り値を使用したコード例です。
package main
import (
"fmt"
)
func test(i int) (a, b int) {
a = i + 4
b = i - 4
return // 名前付き戻り値は、最後にreturnと書くことで値を返せる
}
func main() {
x, y := test(24)
fmt.Println(x) // 28
fmt.Println(y) // 20
}
複数の戻り値のメリット
複数の戻り値は、エラーをチェックする際に非常に有効です。
段階的にエラーをチェックすると、プログラムの流れが楽になり、ネストされた複雑なエラーチェックなどを省略することができます。
複数の戻り値はそれぞれを別々に返すので、パックされた構造体からデータを解凍する必要性を減らすことができます。また、データへのポインタを返す必要も少なくなります。
戻り値をスキップする方法
Golangでは複数の戻り値を無視することもできます。
スキップ演算子(アンダーバー)というリテラルがあり、これを変数の代わりに使用すると、本来その変数に入る値が完全にスキップされます。
以下は、戻り値をスキップしているコード例です。
package main
import (
"fmt"
)
func test(i int) (int, int) {
return i * 2, i * 4
}
func main() {
x, _ := test(24) // スキップ演算子(アンダーバー)によって2つ目の戻り値を無視できる
fmt.Println(x) // 48
}
戻り値をスキップする必要性とは
Golangには変数を初期化して使わない場合、コンパイラがエラーを出す機能があります。そのため、戻り値をすべて変数に格納して使わない場合、このエラーは非常に厄介となります。
けれどもこの問題は、変数をスキップすることで回避することができます。以下はまさにそれを示す例です。
複数の戻り値によるエラー処理
Golangは、複数の戻り値に対する優れたエラー処理をサポートしています。
シンプルに、関数で何らかの処理を行った時にエラーを返すことができ、以下のように順次エラーをチェックします。
package main
import (
"errors"
"fmt"
)
func test(i int) (int, error) {
if i == 0 {
return 0, errors.New("ゼロは使えません")
} else {
return i * 2, nil
}
}
func main() {
result, err := test(0)
if err != nil { // ここでエラーをチェックする
fmt.Println("Error!!!")
} else {
fmt.Println(result)
}
}
出力結果は以下の通りです。
$ go run main.go
Error!!!