Arrayのリファレンスの中に記載がなかったので、試してみました。「動かしてみりゃわかるだろ!」という側面はあると思いますが、備忘録的に一応記事にさせていただきます。
環境
Siv3D v0.6.16
はじめに
Array<int32> numbers(32);
事前に要素数32を確保したSiv3Dの配列Array<int32>
をターゲットとして使っていくことにします。
Array<T>.each_index()
対象の配列に対して関数を登録し、関数の引数で各インデックス及び要素を取得しながら、処理を適用させることのできるメンバ関数です。C#のForEach()
、JavaScriptのmap()
とおんなじ。
ただ、ちょっとした落とし穴があります。それが公式によるDoxygenのコメントで、
全ての要素とそのインデックスを順番に引数にして関数を呼び出します。
とありますが、実際の引数は インデックス、要素 の順で渡されるところです。これを忘れていてなんかエラーが出ていたら、引数を逆にしてみるところから試してみるといいかもです。
numbers.each_index([](int i, int32 &element) { element = i }; );
このように、配列の要素に値を代入するときに使うことができます。
もちろん引数はauto
で型推論すればいいんですが、IntelliSenceが怪しいときもあったので、おかしくなりそうなときはそのまま型名を明記しましょう。
Array<T>.each()
対象の配列に対して関数を登録し、関数の引数で各要素を取得しながら、処理を適用させることのできるメンバ関数です。
本来はeach_index()
より先にこっちを紹介すべきだとは思いますが、あっちの方を値をセットする用途として使いたかったので先にしました。
引数が要素のみになっただけで、使い方はeach_index()
と変わりませんね。
numbers.each([](int32 &element) { ++element *= 2 }; );
この例では、各要素に対してその値をインクリメントしてから2をかけています。全ての要素に対して何か共通処理をしたいときに便利です。
実は>>
が似た機能を持っているが……
Array
クラスでは>>
演算子がオーバーロードされていて、each()
と同じように使うことができますが、
全ての要素に関数を適用した新しい配列を受けとる
Array<int32> evens = numbers >> [](int32 element) { return ++element *= 2; };
戻り値のない処理をする
numbers >> [](int32 element) { Console << element; };
こっちはconst
メンバ関数としてマークされているので、左辺値参照で直接要素を書き換えることはできません。
関数を適用した結果を反映したい場合は、ラムダ式内部で値を返してやって、新しい配列を生成するようにしましょう。その後、それを代入すれば良いです。
このように、新しい配列を生成するときや、要素の書き換えをしないときに使うのが向いてます。
まとめ
for分の方がシンプルに速い局面があるのは否めませんが、ワンライナーで書けたり、書き方を考慮すれば可読性が高くなったり意図が分かりやすくなったりするので、うまく使っていきたいですね。