1. nak2yoshi

    Posted

    nak2yoshi
Changes in title
+writeln()に死す
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,207 @@
+* 以下のコードは、dmd2.067.1で動作を確認しました。
+* __まあたらしい内容はありません__、ご注意ください
+
+# __配列の全要素を表示する(ループ)__
+
+配列の中身を表示するのを愚直にやると、
+ブラケットで囲って、ループで回して、要素をカンマで区切って、
+こんな感じでやると思います。
+
+```lang:D
+import std.stdio;
+
+// 一次元配列の表示関数
+void writeArray(int[] arr)
+{
+ "[".write;
+ foreach (elem; arr[0 .. $ - 1])
+ {
+ elem.write;
+ ", ".write;
+ }
+ arr[$ - 1].write;
+ "]".write;
+}
+
+// 二次元配列の表示関数
+void writeMatrix(int[][] mat)
+{
+ "[".write;
+ foreach (elem; mat[0 .. $ - 1])
+ {
+ elem.writeArray;
+ ", ".write;
+ }
+ mat[$ - 1].writeArray;
+ "]".write;
+}
+
+void main()
+{
+ auto arr = [0, 1, 2, 3, 4];
+ auto mat = [[0, 1], [2, 3], [4, 5]];
+ arr.writeArray;
+ writeln("");
+ mat.writeMatrix;
+}
+```
+
+```lang:Console
+[0, 1, 2, 3, 4]
+[[0, 1], [2, 3], [4, 5]]
+```
+
+# __テンプレート化(再帰+ループ)__
+ここで`writeArray`と`writeMatrix`は、構造がほとんど同じなので
+テンプレート関数を使って一つにまとめます。
+`std.traits`の`isArray`テンプレートを使用して、
+配列かそうでないかの場合分けをしています。
+
+```lang:D
+import std.stdio, std.traits;
+
+// 多次元配列の表示関数
+void writeMatrix(M)(M mat)
+{
+ void writeArray(A)(A arr)
+ {
+ static if (isArray!A)
+ {
+ "[".write;
+ foreach (elem; arr[0 .. $ - 1])
+ {
+ writeArray(elem);
+ ", ".write;
+ }
+ writeArray(arr[$ - 1]);
+ "]".write;
+ }
+ else
+ {
+ arr.write;
+ }
+ }
+ writeArray(mat);
+ writeln("");
+}
+
+void main()
+{
+ auto arr = [0, 1, 2, 3, 4];
+ int[2][3] mats = [[0, 1], [2, 3], [4, 5]];
+ auto matd = [[0, 1], [2, 3], [4, 5]];
+ arr.writeMatrix;
+ mats.writeMatrix;
+ matd.writeMatrix;
+}
+```
+
+```lang:Console
+[0, 1, 2, 3, 4]
+[[0, 1], [2, 3], [4, 5]]
+[[0, 1], [2, 3], [4, 5]]
+```
+
+次元を下げながら再帰をしていき、配列ではなくなったら
+値を表示するという処理の流れです。
+テンプレート化の効能として、多次元、及び静的配列にも対応することができました。
+(ネスト関数をUFCSできないのが悔しいですね。。。)
+
+# __文字列操作バージョン__
+
+構造はずいぶんスッキリしましたが、
+都度、標準出力に`write`しているのはイケてない気もします。
+表示する内容の文字列をあらかじめ作成しておき、
+最後に`writeln`するように変更してみましょう。
+
+```lang:D
+import std.stdio, std.traits, std.conv;
+
+void writeMatrix(M)(M mat)
+{
+ string result;
+ void inner(A)(A arr)
+ {
+ static if (isArray!A)
+ {
+ result ~= "[";
+ foreach (elem; arr[0 .. $ - 1])
+ {
+ inner(elem);
+ result ~= ", ";
+ }
+ inner(arr[$ - 1]);
+ result ~= "]";
+ }
+ else
+ {
+ result ~= arr.to!string;
+ }
+ }
+ inner(mat);
+ result.writeln;
+}
+```
+
+# __やったか?!__
+
+`std.string.join`で、ブラケットとカンマ区切りの加工を行い、
+`std.string.map`で、ループ処理をすればもっと簡単になりそうです。
+
+```lang:D
+import std.stdio, std.traits, std.conv, std.string, std.algorithm;
+
+void writeMatrix(M)(M mat)
+{
+ string inner(A)(A arr)
+ {
+ static if (isArray!A)
+ return ["[", "]"].join( arr.dup.map!( elem => inner(elem) ).join(", ") );
+ else
+ return arr.to!string;
+ }
+ inner(mat).writeln;
+}
+```
+
+※`dup`がないと静的配列の場合にエラーになるようです。
+なにはともあれ、よかったよかった。
+
+# __あ、手がすべっtt__
+
+「あっ」
+
+```lang:D
+import std.stdio;
+
+void main()
+{
+ auto arr = [0, 1, 2, 3, 4];
+ int[2][3] mats = [[0, 1], [2, 3], [4, 5]];
+ auto matd = [[0, 1], [2, 3], [4, 5]];
+
+ arr.writeln;
+ mats.writeln;
+ matd.writeln;
+}
+```
+
+```lang:Console
+[0, 1, 2, 3, 4]
+[[0, 1], [2, 3], [4, 5]]
+[[0, 1], [2, 3], [4, 5]]
+```
+
+__「・・・」__
+
+__「・・・」__
+
+__「(普通にwritelnで出るじゃん・・・)」__
+
+# __【結論】__
+
+__D言語の`writeln`関数は、多次元配列も表示してくれます。__
+__とても便利! 皆さんどんどん使いましょう!__
+
+# __次回、「to!(int[])に死す」。デュエルスタンバイ!(続きません)__
+