Golangの関数について

Golang

関数は、どのプログラミング言語においても必要不可欠なものです。関数は、コードを構造化し、日常的な作業を容易にします。

Goは、「ファーストクラス関数」をサポートしています。つまり、Goの関数は、変数に代入したり、引数として渡したり、他の関数から返したりすることができます。

関数の宣言と呼び出し

関数を宣言するには、funcキーワードを使います。関数宣言の一般的な構造を以下に示します。

func nameOfFunction(arguments) (returnTypes) {
  // body
}

コンソールに “Hello World!”と表示する関数を書いてみましょう。

package main
 
import (
    "fmt"
)
 
func main() {
    helloWorld()  // call function
}
 
func helloWorld() {                  // declare the function
    fmt.Println("Hello World!")  // prints "Hello World!" 
}

ご覧のように、関数を呼び出すのはとても簡単です。

returnの型と引数

Goの関数は、任意の戻り値の型と任意の引数の型を持つことができます。これらを宣言する方法を見てみましょう。

package main
 
import (
    "fmt"
)
 
func main() {
    greetUser("John")             // prints "Hello, John"
    fmt.Println(add10(12))        // prints 22
}
 
func greetUser(user string) {
    fmt.Printf("Hello, %s\n", user)
}
 
func add10(value int) int {
    return value + 10
}

上のコードでは、greetUser()関数は戻り値の型が宣言されていません。しかし、string型の引数が与えられています。関数add10()では、パラメータはint型であり、戻り値もint型です。

関数内の複数の引数

関数の内部では、複数の引数を渡すことができます。その方法の例を見てみましょう。

package main
 
import (
    "fmt"
)
 
func main() {
    showAge("Paul", 22)                      // prints "Paul is 22 years old."
    fmt.Println(multiplyTwoNumbers(12, 23))  // prints 276
}
 
func showAge(name string, age int) {
    fmt.Printf("%s is %d years old.\n", name, age)
}
 
func multiplyTwoNumbers(x, y int) int {          // same type of arguments 
    return x*y
}

複数の戻り値を持つGoの関数

関数は、必要な数の値を返すことができます。ここでは、その方法を示す例を紹介します。

package main
 
import (
    "fmt"
)
 
func main() {
    vAdd, vSub := addSub(35, 25)
    fmt.Printf("35 + 25 = %d\n", vAdd)    // prints "35 + 25 = 60"
    fmt.Printf("35 - 25 = %d\n", vSub)    // prints "35 - 25 = 10"
}
 
 
func addSub(x, y int) (int, int) {        // multiple return values (int, int)
    return x+y, x-y
}

Goでの名前付き戻り値

GoLangでは、関数の戻り値に名前を付けることができます。これは、変数の名前を言及することができますので ここでは、それを行う例を紹介します。

package main
 
import (
    "fmt"
)
 
func main() {
    fmt.Println(divby10(100))
}
 
func divby10(num int) (res int) {
    res = num/10
    return res
}

「値」と「参照」による関数

Goでは、関数はパラメータを値または参照で受け取ることができます。値を取る場合はどうなるか見てみましょう。

package main
 
import (
    "fmt"
)
 
func main() {
    val := 12
    fmt.Printf("The value before function call is %d\n", val)
    changeValue(val)         // does not change value
    changeValueByRef(&val)   //changes value
    fmt.Printf("The value after function call is %d\n", val)
}
 
func changeValue(num int) {
    num = 42
}
 
func changeValueByRef(num *int) {
    *num = 42
}

上のコードでは、関数が値を受け取るときには、値をまったく変更しません。しかし、参照を取ると値が変わります。

関数からエラーを返す

関数はエラーを返すことができます。エラーは、予期せぬことが起こったことを示す手段です。だから、それを持つことが必要なのです。

空白識別子の使用

空白の識別子が使われているのは、変数が宣言されているのに使われていないと、Goが警告を出すからです。構文としては、「_」を使って値を代入します。

package main
 
import (
    "fmt"
)
 
func main() {
    j, _ := returnTwoNumbers()   // ignores the second return value
    fmt.Println(j)
}
 
func returnTwoNumbers() (int, int) {
    return 12, 23
}

Golangの無名関数

Goはファーストクラス関数をサポートしているので、関数を変数に代入したり、すぐに呼び出したりすることができます。以下にコード例を示します。

package main
 
import (
    "fmt"
)
 
func main() {
     
    getMod := func(a, b int) (int) {         // declare it
        return a%b
    }
     
    fmt.Println(getMod(12, 5))               // prints 2
                                             // call by its name
}

関数の即時呼び出し

以下のコードでは、無名関数が直ちに呼び出されています。

package main
 
import (
    "fmt"
)
 
func main() {
     
    func(name string) {
        fmt.Printf("Hello, %s", name)
    }("John")   // prints "Hello, John"
}

「defer」キーワードについて

“Defer “は、関数の呼び出しを周囲の関数が戻るまで遅らせるキーワードです。

package main
 
import "fmt"
 
func main() {
    defer fmt.Println("before this.")   // runs at the end
    fmt.Println("This is printed ")     // runs first
}

ユーザー定義のファンクションタイプ

ユーザー定義関数型は、関数として識別できる型です。以下はその例です。

package main
 
import (
    "fmt"
)
 
type First func(int) int     // declare type
 
func getFunction() First {   // use it
    return func(val int) int {
        return val * 5
    } 
}
 
func main() {
     
    f := getFunction()  // returns a function of type First
    fmt.Println(f(12))
}

引数としての機能

Goの関数は、引数として渡すことができます。これにより、高階の関数を作ることができます。

関数から関数を返す

関数は、別の関数を返すこともできます。その方法をご紹介します。

package main
 
import (
    "fmt"
)
 
func main() {
    f := getFunction("John") // returns a function
    f()                      // prints "Hello, John"
}
 
func getFunction(name string) func() {
    return func() {
        fmt.Printf("Hello, %s", name)
    }
}

関数クロージャーについて

関数クロージャは、理解すべき重要な概念です。よりよいコードを作成したり、言語に対する理解を深めたりするのに役立ちます。

では、クロージャとは何でしょうか?

クロージャとは、そのスコープ内の変数に束縛される関数のことです。つまり、それぞれのクロージャが独自のスコープを持っているということです。

タイトルとURLをコピーしました