🔖

Goで配列操作をラップする!JavaScriptライクなArrayメソッドを実現するパッケージを開発してみた

2025/01/26に公開2

はじめに

Go言語で配列やスライスを操作する際、標準ライブラリではシンプルな方法が提供されています。しかし、複雑な処理を行うときには多くのコードを書かなければならず、可読性や開発効率が落ちる場合があります。

JavaScriptのArrayメソッド(map, filter, reduce, find, some など)は直感的で強力ですが、Goにはそのような高レベルの操作を簡単に実現する仕組みがありません。
そこで、JavaScriptの配列メソッドと同じ感覚で操作できるGoパッケージを開発しました!この記事では、このパッケージの特徴や使い方について紹介します。

パッケージ開発の背景

Goのシンプルな配列操作に対する課題として、繰り返し処理や条件付き抽出を毎回手書きするのが面倒だったことが挙げられます。一部のライブラリは提供されていますが、汎用性や直感的なインターフェースに欠ける場合が多いです。

そのため、JavaScriptのArrayメソッドが非常に使いやすいと感じていた私は、Goでも同様の感覚で操作できるようにしたいと考え、このパッケージを開発しました。

このパッケージの特徴

Go 1.18で導入されたジェネリクスを活用しています。これにより、型を指定して安全に配列操作ができ、異なる型の配列にも汎用的に対応可能です。

シンプルなインターフェース

map, filter, reduce などの関数をスライス型に関連付けたメソッドとして利用可能です。

可読性の向上

一連の配列操作をチェーン可能にすることで、より簡潔で直感的なコードを書けるようになります。

使い方

パッケージをインストールするには以下を実行してください。

go get github.com/hiroky1983/array-method

次に、プロジェクトでパッケージをインポートします。

import "github.com/hiroky1983/array-method/array"

importしたarrayパッケージから各、メソッドを呼び出します。
メソッドによって異なりますが、基本的に

  • 第一引数に基となる配列
  • 第二引数に関数を処理する条件

を記述します。

以下はこのパッケージを使ったサンプルコードです。

package main

import (
	"fmt"
	"github.com/hiroky1983/array-method"
)

func main() {
	arr := []int{1, 2, 3, 4, 5}
	mapped := array.Map(arr, func(v int) int {
		return v * 3
	})
	fmt.Println("Mapped:", mapped) // Output: [3 6 9 12 15]
}

実装されているメソッドの紹介

Map: スライスの各要素に関数を適用して新しいスライスを生成します。
Filter: 条件を満たす要素のみを含む新しいスライスを生成します。
Reduce: スライスの要素を累積的に処理し、1つの値にまとめます。
Find: 条件を満たす最初の要素を返します。条件を満たす要素がない場合は、nilを返します。
FindIndex: 条件を満たす最初の要素のインデックスを返します。条件を満たす要素がない場合は、-1を返します。
ForEach: スライスの各要素に対して、指定された処理を順次実行します。
Some: スライス内に条件を満たす要素が1つでも存在する場合にtrueを返します。

sample struct

デバッグ用のサンプル構造体を定義する

type Person struct {
	Name string
	Age  int
}

type PersonPointer struct {
	Name *string
	Age  *int
}

type NewPerson struct {
    Person Person
    IsAdult bool
}

Filter

条件に一致する要素だけを抽出して新しい配列を返すメソッドです。

function interface

Filter[T any](slice []T, condition func(T) bool) []
evenNumbers := array.Filter(nums, func(n int) bool {
    return n%2 == 0
    })
fmt.Println(evenNumbers) // Output: [{{Alice 25} true} {{Bob 30} true} {{Charlie 15} false} {{David 18} false} {{Eve 21} true}]

Map

配列の各要素に関数を適用して、新しい配列を作成します。
function interface

Map[Input any, Output any](slice []Input, transform func(Input) Output) []Output
nums := []int{1, 2, 3, 4, 5}
doubled := array.Map(nums, func(n int) int {
    return n * 2
})
fmt.Println(doubled) // Output: [2 4 6 8 10]

Find

条件に一致する最初の要素を検索します。
function interface

Find[T any](slice []T, condition func(T) bool) *T
people := []Person{
    {"Alice", 25},
    {"Bob", 30},
}
person := array.Find(people, func(p Person) bool {
    return p.Name == "Alice"
})
fmt.Println(person) // Output: &{Alice 25}

FindIndex

条件に一致する最初の要素のインデックスを検索します。
function interface

FindIndex[T any](slice []T, condition func(T) bool) int
people := []Person{
    {"Alice", 25},
    {"Bob", 30},
}
index := array.FindIndex(people, func(p Person) bool {
    return p.Name == "Bob"
})
fmt.Println(index) // Output: 1

ForEach

配列の各要素に対してアクションを実行します。
function interface

ForEach[T any](slice []T, callback func(T))
people := []Person{
    {"Alice", 25},
    {"Bob", 30},
}
array.ForEach(people, func(p Person) {
    fmt.Println(p.Name)
})
// Output: Alice Bob

Reduce

配列の要素を累積して一つの値を生成します。
function interface

Reduce[T any, U any](slice []T, reducer func(U, T) U, initial U) U
nums := []int{1, 2, 3, 4, 5}
sum := array.Reduce(nums, func(prev int, current int) int {
    return prev + current
}, 0)
fmt.Println(sum) // Output: 15

Some

少なくとも一つの要素が条件を満たすかどうかを確認します。
function interface

Some[T any](slice []T, condition func(T) bool) bool
nums := []int{1, 2, 3, 4, 5}
result := array.Some(nums, func(n int) bool {
    return n%2 == 0
})
fmt.Println(result) // Output: true

おわりに

このパッケージを利用することで、GoでもJavaScriptのように直感的に配列を操作できるようになります。ぜひこのパッケージを試してみて、フィードバックをいただければ幸いです!
GitHubリポジトリはこちら
https://github.com/hiroky1983/array-method

Go packages
https://pkg.go.dev/github.com/hiroky1983/array-method#section-readme

開発についての補足

このパッケージは個人開発のプロジェクトで、現在も機能の追加や改修を積極的に行っています。
本来、jsでは第二引数でindexが取れるのですが、それが取れなかったりするので今後アップデートしていきます。
今後のアップデートでは、さらに多くの配列操作メソッドやユースケースに対応する予定です。ご意見やフィードバックをいただければ、機能拡充の参考にさせていただきます。

Discussion