🦔
GoのGenericsで便利関数を作成する
はじめに
HITOTSU株式会社の河村康治です。
今回はタイトルにもある通り、GoのGenericsを活用した便利関数を紹介します。
Contains
スライス内に特定の要素が含まれるかを検知する関数です。
main.go
package main
import "fmt"
// Contains はスライスに特定の要素が含まれているか確認
func Contains[T comparable](slice []T, target T) bool {
for _, v := range slice {
if v == target {
return true
}
}
return false
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
fmt.Println(Contains(numbers, 3)) // true
fmt.Println(Contains(numbers, 10)) // false
words := []string{"apple", "banana", "cherry"}
fmt.Println(Contains(words, "banana")) // true
}
実行結果
~/go/go_generics/sample/contains (main)$ go run main.go
true
false
true
スライスと比較する値の型が異なる場合
スライスと比較する値の型が異なる場合は下記のようなコンパイルエラーが発生します
Filter関数
スライス内から特定の条件で絞り込みをかける関数です。
main.go
package main
import "fmt"
// Filter はスライスから条件を満たす要素を抽出
func Filter[T any](slice []T, predicate func(T) bool) []T {
var result []T
for _, v := range slice {
if predicate(v) {
result = append(result, v)
}
}
return result
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
even := Filter(numbers, func(n int) bool { return n%2 == 0 }) // 偶数を抽出
fmt.Println(even) // [2, 4]
words := []string{"apple", "banana", "cherry"}
withA := Filter(words, func(s string) bool { return len(s) > 5 }) // 5文字より長い文字列を抽出
fmt.Println(withA) // ["banana", "cherry"]
}
実行結果
~/go/go_generics/sample/contains (main)$ go run main.go
[2 4]
[banana cherry]
Mapの辞書操作
Mapの辞書操作を実施する関数です。KeyやValue値を抽出します
Keyの抽出
main.go
package main
import "fmt"
// Keys はマップから全てのキーを取得
func Keys[K comparable, V any](m map[K]V) []K {
keys := make([]K, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}
func main() {
m := map[string]int{"Alice": 30, "Bob": 25, "Charlie": 35}
fmt.Println(Keys(m)) // ["Alice", "Bob", "Charlie"]
}
実行結果
~/go/go_generics/sample/contains (main)$ go run main.go
[Alice Bob Charlie]
Valueの抽出
main.go
package main
import "fmt"
// Values はマップから全ての値を取得
func Values[K comparable, V any](m map[K]V) []V {
values := make([]V, 0, len(m))
for _, v := range m {
values = append(values, v)
}
return values
}
func main() {
m := map[string]int{"Alice": 30, "Bob": 25, "Charlie": 35}
fmt.Println(Values(m)) // [30, 25, 35]
}
実行結果
~/go/go_generics/sample/map (main)$ go run main.go
[30 25 35]
数値操作
Sum関数
main.go
package main
import "fmt"
// Sum は数値スライスの合計を計算
func Sum[T int | float64](slice []T) T {
var sum T
for _, v := range slice {
sum += v
}
return sum
}
func main() {
ints := []int{1, 2, 3, 4, 5}
fmt.Println(Sum(ints)) // 15
floats := []float64{1.1, 2.2, 3.3}
fmt.Println(Sum(floats)) // 6.6
}
実行結果
~/go/go_generics/sample/sum (main)$ go run main.go
15
6.6
その他操作
Reduce関数
main.go
package main
import "fmt"
// Reduce はスライスを1つの値に集約
func Reduce[T any, U any](slice []T, initial U, accumulator func(U, T) U) U {
result := initial
for _, v := range slice {
result = accumulator(result, v)
}
return result
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
sum := Reduce(numbers, 0, func(acc int, n int) int { return acc + n })
fmt.Println(sum) // 15
words := []string{"Go", "is", "awesome"}
concat := Reduce(words, "", func(acc string, s string) string { return acc + s + " " })
fmt.Println(concat) // "Go is awesome "
}
実行結果
~/go/go_generics/sample/reduce (main)$ go run main.go
15
Go is awesome
最後に
簡単に作れて便利なので一度試してみてください!
Discussion