こんにちは、開発チームでエンジニアをしている和田です。
普段の業務ではバックエンドは Node.js 、フロントエンドは Vue.js を使って開発することが多く、JS・TSな毎日を過ごしています。 最近、N2i では「毎朝15分で Go 言語を習得する」という勉強会が開催されており、Go 言語について学ぶ機会が増えました。
というわけで、今回は Go 言語の初学者を対象に Go 言語のコンセプトを理解しつつ、JavaScript の配列のメソッドを Go 言語で再現する方法について紹介します💪
Go 言語 のコンセプトに触れる
People illustrations by Storyset
Go 言語というと、Google社が開発した「シンプルで効率的なコードが書けるプログラミング言語」というイメージが強いのではないでしょうか?
実際に書いてみると文法も簡単で覚えることも少なく、コンセプト通りシンプルなコードを書くことができます。
しかしながら、シンプルがゆえにビルトインのメソッドは少なく、JavaScript の配列で使用する map()
や filter()
などのメソッドは用意されていません。
ループ系の処理は全て for
のみによって記述します。
Go をうまく書くには、その特性やイディオムを理解することが重要です。また、名前付けや書式、プログラムの組み立て方など、Goでプログラミングするための定石を知ることで、他のGoプログラマーが理解しやすいプログラムを書くことができます。 Effective Go より
上述の通り、シンプルな文法をイディオマティックに使いこなすことがこの言語のカギと言えます。
JavaScript の配列メソッドを Go 言語で再現する
では、本題に参りましょう。ここからは JavaScript の各種配列メソッドを紹介しながら、それらを Go 言語で記述していきます。
実行環境は Go 言語 が v1.20.1
、Node.js が v16.15.0
です。
下記の6つのメソッドについてそれぞれ解説していきます。
- map
- filter
- find
- findIndex
- every
- some
map メソッド
JavaScript の map メソッドは、配列の要素に対して任意の処理を適応することができるメソッドです。 下記の JavaScript のコード では、int 型の配列の各要素をそれぞれ2倍にして返す処理が記述されています。
const numbers = [1, 2, 3, 4, 5]; const results = numbers.map((number) => number * 2); console.log(results); // [ 2, 4, 6, 8, 10 ]
こちらのコードを Go 言語で実装すると下記のようになります。
package main import "fmt" type ints []int func (numbers ints) Map(mapFunc func(number int) any) []any { var val []any for _, num := range numbers { val = append(val, mapFunc(num)) } return val } func main() { numbers := ints{1, 2, 3, 4, 5} results := numbers.Map(func(num int) any { return num * 2 }) fmt.Println(results...) // 2 4 6 8 10 }
処理の内容としては
- int型の要素で構成されたスライス ints 型を定義する
- ints 型に Map メソッドを実装する
- main 関数内で ints 型のスライスを宣言して、Map メソッドの返値を変数
results
に格納する results
の値を表示する
となっています。
Map メソッドは引数として、「int 型を受け取り任意の型で返す」関数 mapFunc
を受け取り、対象の配列の各要素に mapFunc
を実行し、val
として返します。
呼び出し側で return num * 2
の箇所に要素に実行したい処理を書けば応用できますね。
filter メソッド
JavaScript の filter メソッドは、配列の各要素に対して、指定された条件に当てはまる要素のみを返すメソッドです。 下記の JavaScript のコードでは、偶数のみを返す処理が記述されています。
const numbers = [1, 2, 3, 4, 5]; const results = numbers.filter((number) => number % 2 === 0); console.log(results); // [ 2, 4 ]
こちらを Go 言語で実装すると下記のようになります。
package main import "fmt" type ints []int func (numbers ints) Filter(filterFunc func(number int) bool) []any { var val []any for _, num := range numbers { if filterFunc(num) { val = append(val, num) } } return val } func main() { numbers := ints{1, 2, 3, 4, 5} results := numbers.Filter(func(num int) bool { return num%2 == 0 }) fmt.Println(results...) // 2 4 }
Map メソッドのときと同様に、独自で定義した ints 型に対して、Filter メソッドを実装しています。
filterFunc
は「int 型を受け取りbool型を返す」関数です。この filterFunc
が true
を返すものだけを新たに作成するスライスに格納して返す処理を行います。
find メソッド
続いて find メソッドです。
JavaScript の find メソッドは、配列の要素の中で、指定された条件に当てはまる最初の要素を返すメソッドです。 下記のコードで、最初の偶数を返す処理を記述しています。
const numbers = [1, 2, 3, 4, 5]; const result = numbers.find((number) => number % 2 === 0); console.log(result); // 2
こちらを Go 言語で書くと...
package main import "fmt" type ints []int func (numbers ints) Find(findFunc func(number int) bool) int { var val int for _, num := range numbers { if findFunc(num) { val = num break } } return val } func main() { numbers := ints{1, 2, 3, 4, 5} result := numbers.Find(func(num int) bool { return num%2 == 0 }) fmt.Println(result) // 2 }
filter メソッドと似ていますね。
ポイントは、Find メソッドの中で for ループを実行し、findFunc
の条件に当てはまったら break
を使ってループを抜け出す点です。
この処理によって、条件に当てはまる最初の要素のみを返す事ができます。
findIndex メソッド
JavaScript の findIndex メソッドは、配列の要素の中で、指定された条件に当てはまる最初の要素のインデックスを返すメソッドです。
下記のコードで、最初の3の倍数のインデックスを返します。実行結果は2になりますね。
const numbers = [1, 2, 3, 4, 5]; const result = numbers.findIndex((number) => number % 3 === 0); console.log(result); // 2
こちらも Go 言語で書くと...
package main import "fmt" type ints []int func (numbers ints) FindIndex(findFunc func(number int) bool) int { var val int for i, num := range numbers { if findFunc(num) { val = i break } } return val } func main() { numbers := ints{1, 2, 3, 4, 5} result := numbers.FindIndex(func(num int) bool { return num%3 == 0 }) fmt.Println(result) // 2 }
Find メソッドと異なる点は、for ループでインデックス i
を使用して、findIndexFunc
の条件に当てはまる場合にインデックスを返す点です。
ほとんど同じ記述なので簡単ですね👍
every メソッド
JavaScript の every メソッドは、配列の全ての要素が指定された条件に当てはまるかどうかを真偽値で返すメソッドです。
下記のコードで、「全ての要素が偶数であるか?」・「全ての要素が10未満であるか?」を調べて真偽値で返しています。
const numbers = [1, 2, 3, 4, 5]; const resultA = numbers.every((number) => number % 2 === 0); const resultB = numbers.every((number) => number < 10); console.log(resultA); // false console.log(resultB); // true
Go 言語で書くと下記のようになります。
package main import "fmt" type ints []int func (numbers ints) Every(everyFunc func(number int) bool) bool { val := true for _, num := range numbers { if !everyFunc(num) { val = false break } } return val } func main() { numbers := ints{1, 2, 3, 4, 5} resultA := numbers.Every(func(num int) bool { return num%2 == 0 }) resultB := numbers.Every(func(num int) bool { return num < 10 }) fmt.Println(resultA) // false fmt.Println(resultB) // true }
Every メソッドの中で、最初に返値 val
を true
としておき、everyFunc
の条件に当てはまらないものが1つでもあった場合ループを抜けて false
で返します。
some メソッド
最後に、some メソッドです。
JavaScript の some メソッドは every メソッドと対照的に、配列の要素が1つでも指定されたの条件に当てはまるかどうかを真偽値で返すメソッドです。
下記のコードで、「全ての要素が偶数であるか?」・「全ての要素が10より大きいか?」を調べて真偽値で返しています。
const numbers = [1, 2, 3, 4, 5]; const resultA = numbers.some((number) => number % 2 === 0); const resultB = numbers.some((number) => number > 10); console.log(resultA); // true console.log(resultB); // false
Go 言語で書いてみましょう。
package main import "fmt" type ints []int func (numbers ints) Some(someFunc func(number int) bool) bool { val := false for _, num := range numbers { if someFunc(num) { val = true break } } return val } func main() { numbers := ints{1, 2, 3, 4, 5} resultA := numbers.Some(func(num int) bool { return num%2 == 0 }) resultB := numbers.Some(func(num int) bool { return num > 10 }) fmt.Println(resultA) // true fmt.Println(resultB) // false }
Every メソッドと異なる点は、返値 val
を false
としておき、someFunc
の条件に当てはまるものが1つでもあった場合ループを抜けて true
で返します。
everyFunc
とまったく逆の処理ですね。
【まとめ】Go 言語はイディオムの理解が大切
最後まで読んでくださりありがとうございました!
以上が、JavaScript の各種配列メソッドを Go 言語で実装した解説です。
今回は普段良く使う JavaScript の配列メソッドを中心に Go 言語で再現してみました。
JavaScript の配列メソッドは他にもありますし、Go 言語での再現方法も様々なやり方があると思います。
シンプルがゆえに長いコードとなりましたが、何より読みやすくどんな処理を実行するのかハッキリわかるのが Go 言語のいいところですね。
「〇〇系の処理をするときはこの書き方だ!🤓」
といったように、イディオム的記法を体で覚えてしまえばスムーズに開発できそうなので、日々の学習を続けたいと思います🫡