関数は複数の戻り値をもつことができる
golangの目新しい特徴のひとつとして数えられている。
関数は、括弧でリストすることで複数の値を持かえすことができる。返された値は、変数リストへ代入して格納する。
(int, int) が返す値を括弧でリストしている部分。
func 関数名 引数 戻り値 の順番になる。
func f(a int, b int) (int, int) {
c := a + b
d := a * b
return c, d
}
func main() {
a := 100
b := 100
c,d := f(a, b)
fmt.Println(c)
fmt.Println(d)
}
output
200
10000
戻り値を複数定義できる形式はエラーハンドリングにも一役かっている
func doSomething(input int) (result string, err error) {
switch {
case input < 0:
return "", fmt.Errorf("%d is minus value", input)
case input < 10:
return "less than 10", nil
default:
return "greater than 10", nil
}
}
func main() {
if r, err := doSomething(-1); err != nil {
fmt.Println(err)
} else {
fmt.Println(r)
}
}
output
-1 is minus value
匿名関数
golangは匿名関数をサポートしている
funcから始まる関数リテラルは匿名関数をあらわし、変数に代入することが可能。
func main() {
fn := func() {
fmt.Println("hello")
}
fn()
}
output
hello
匿名関数を関数の引数にとしてわたすことも可能
func sumOf(f func(int) int, n, m int) int {
a := 0
for ; n <= m; n++ {
a += f(n)
}
return a
}
func main() {
square := func(x int) int { return x * x }
fmt.Println(square(10))
a := func(x int) int { return x * x }(10)
fmt.Println(a)
fmt.Println(sumOf(square, 1, 100))
fmt.Println(sumOf(func(x int) int { return x * x }, 1, 100))
}
output
100
100
338350
338350
クロージャ
関数リテラルはクロージャになっている。
そのため関数リテラル内から外側の関数内で定義した変数を参照可能になる。
これらの変数は外側の関数と、関数リテラル間で共有され、これらからアクセス可能な限り存続する。
func main() {
x := 5
fn := func() {
fmt.Println("x is", x)
}
fn()
x++
fn()
}
output
x is 5
x is 6
func intSeq() func() int {
i := 0
return func() int {
i += 1
return i
}
}
func main() {
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
newInts := intSeq()
fmt.Println(newInts())
}
output
1
2
3
1