🗺️
Goでmap関数を実装してみる
TL;DR
package main
import (
"fmt"
"iter"
"slices"
)
func Map[S, T any, C func(S) T](c C, src iter.Seq[S]) iter.Seq[T] {
return func(yield func(T) bool) {
for s := range src {
if !yield(c(s)) {
break
}
}
}
}
func twice(n int) int {
return 2 * n
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
result := slices.Collect(Map(twice, slices.Values(numbers)))
fmt.Printf("%+v\n", result)
}
Goでもmap()を使いたい
PythonとかRustとかTypeScriptで使えるmap
が便利なのでGoでも使いたくなります。
Go 1.23.0でイテレータを扱えるようになり、Pythonのmap
関数と同等の機能が実現できるようになったのでやってみます。もう何番煎じかわかりませんが...
第一引数に変換関数を、第二引数にイテレータを受け取って、各要素を変換したイテレータを返します。シグネチャはこんな感じです。
(SとTのインターフェース制約はもうちょっと考えた方がいいかも?)
func Map[S, T any, C func(S) T](c C, src iter.Seq[S]) iter.Seq[T] {
...
}
中身はこんな感じです。src
をイテレートして、変換関数C
を適用してyieldするだけです。
func Map[S, T any, C func(S) T](c C, src iter.Seq[S]) iter.Seq[T] {
return func(yield func(T) bool) {
for s := range src {
if !yield(c(s)) {
break
}
}
}
}
スライスの各要素を変換して新たなスライスを作りたいというとき、今までは変換関数とスライスを受け取ってそれを適用する関数をそれぞれ用意しなければなりませんでしたが、イテレータが使えるようになったことで変換関数を1つ用意すればジェネリックに使えるようになりました。(ジェネリクス使えば変換関数は共通化できましたが)
複数の変換関数をチェインすることもできるので便利になったなあと思います。
Discussion