関数
Go 言語の関数:クロージャ、高階関数、再帰。
Closures
クロージャは外部スコープの変数をキャプチャしてアクセスできる無名関数。
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
c := counter()
fmt.Println(c()) // 1
fmt.Println(c()) // 2
fmt.Println(c()) // 3
}- Links
High Order Function
高階関数:関数を引数として受け取る、または関数を返す。
// 関数を引数として受け取る
func apply(nums []int, fn func(int) int) []int {
result := make([]int, len(nums))
for i, v := range nums {
result[i] = fn(v)
}
return result
}
// 使用例
double := func(n int) int { return n * 2 }
nums := []int{1, 2, 3, 4}
doubled := apply(nums, double) // [2, 4, 6, 8]Filter の例
func filter(nums []int, fn func(int) bool) []int {
var result []int
for _, v := range nums {
if fn(v) {
result = append(result, v)
}
}
return result
}
// 使用例
isEven := func(n int) bool { return n%2 == 0 }
evens := filter([]int{1, 2, 3, 4, 5, 6}, isEven) // [2, 4, 6]Reduce の例
func reduce(nums []int, fn func(int, int) int, initial int) int {
result := initial
for _, v := range nums {
result = fn(result, v)
}
return result
}
// 使用例
sum := reduce([]int{1, 2, 3, 4}, func(a, b int) int { return a + b }, 0) // 10Recursion
再帰関数、クロージャも再帰にできる。
// 階乗
func factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n-1)
}
// フィボナッチ数列
func fibonacci(n int) int {
if n <= 1 {
return n
}
return fibonacci(n-1) + fibonacci(n-2)
}クロージャの再帰
var fib func(n int) int
fib = func(n int) int {
if n <= 1 {
return n
}
return fib(n-1) + fib(n-2)
}- Links
Methods
メソッドは型に付加された関数。
Receiver Type
| 種類 | 特性 | 使用場面 |
|---|---|---|
| Value Receiver | 値をコピー、元の値に影響しない | 読み取り操作、小さい struct |
| Pointer Receiver | 元のメモリアドレスを操作 | 変更操作、大きい struct |
type Rectangle struct {
Width, Height float64
}
// Value Receiver - 元の値を変更しない
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Pointer Receiver - 元の値を変更できる
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
func main() {
rect := Rectangle{10, 5}
fmt.Println(rect.Area()) // 50
rect.Scale(2)
fmt.Println(rect.Area()) // 200
}Defer
遅延実行、LIFO(後入れ先出し)順序で実行、リソースのクリーンアップによく使われる。
func readFile(filename string) error {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close() // 関数終了時に自動的にクローズ
// ファイルを読み取り...
return nil
}複数の Defer
func main() {
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
// 出力順序: 3, 2, 1 (LIFO)
}Defer とエラー処理
func doSomething() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered: %v", r)
}
}()
// panic を起こす可能性のある操作...
return nil
}Variadic Functions
可変長引数関数、任意の数の引数を受け取る。
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(sum(1, 2)) // 3
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
// slice を展開
nums := []int{1, 2, 3}
fmt.Println(sum(nums...)) // 6
}Sorting
sort パッケージを使用してソート。
import "sort"
// 基本ソート
nums := []int{3, 1, 4, 1, 5, 9}
sort.Ints(nums) // [1, 1, 3, 4, 5, 9]
strs := []string{"banana", "apple", "cherry"}
sort.Strings(strs) // ["apple", "banana", "cherry"]カスタムソート
type Person struct {
Name string
Age int
}
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35},
}
// 年齢でソート
sort.Slice(people, func(i, j int) bool {
return people[i].Age < people[j].Age
})sort.Interface の実装
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
sort.Sort(ByAge(people))