会得必須!Luaの真髄「テーブル」C言語との親和性、複数の戻り値のサポート、コルーチンと魅力的な機能を沢山持つLuaですが、実はLuaの真髄は「テーブル」にあります。テーブルというのは、イメージするなら以下のような名前がついた変数の塊です:各変数それぞれではなくてこの塊が一つのテーブルです。テーブルはLuaが扱うことができる変数型の一つで、保持している値一つ一つに必ず名前が付けられます。値はLuaが定義する型ならば何でも入れられます。"北海道"};C言語の構造体に似ていますが、あくまでもこういうデータの塊を表しています。tbl型というわけではないので注意です。"東京都";ここまでは、「ん〜、まぁ、データの塊なのね」という感じだと思うのですが、テーブルにはLuaが定義する型ならば何でも入れられるという所に最大のポイントがあります。Luaの変数型には数値や文字列はもちろんですが、関数やテーブルもあります。関数を入れるとはどういう事なのか?次で説明します。Func;C言語で言う関数ポインタのような感覚です。function(str)print(str);endfunctionの後に名前を付けない、いわゆる「無名関数」にするのがポイントです。function(str)print(str);end};こうすると、下のようにテーブルに登録した関数を呼び出せます:tbl.MyFunc("Marupeke");この書き方、「C++にクラスのメソッド呼び出し」に非常に似てますよね。テーブルを使うとLuaでクラスのような書き方ができるようになるんです。C++にある言語仕様のクラスほど頑健では無いのですが、似た様な事ができるんです。ここに、「C++とLuaの連携」という道が見えてきます。クラス宣言+オブジェクト生成をするNew関数テーブルに関数を登録するとクラスのメソッド呼び出しみたいな事ができるようになります。クラスにはもう一つ大切な「メンバ変数」があります。obj2;インスタンスを2つ作れば2つ分の個別データになりますよね。Lua側のテーブルでも同じことをしようと思ったら、テーブルをその度に作る必要があるわけです。「テーブルを作る関数」をLua側に設定する必要があります。作っても良いのですが、どうせならば「クラス名.New()」としたらテーブルが吐き出されるようにしたい所です。この書き方をLuaでするにはクラス名のテーブルを作ればいいんですよね。Data.New();Dataという構造体っぽいテーブルを作ります。中にはNewという名前の関数を保持しています。New関数はテーブルを返しています。Newを呼ぶ度に新しいテーブルが作成されますので、これはインスタンス作成関数になっているわけです。クラスには「メソッド」も必要です。C++のクラスのメソッドは「自分が持っているメンバを使う」という特色があります。Data.New();obj1.print();print関数を新しく定義して、テーブル内の変数を使っているように見えるのですが、これは残念ですがうまく動きません。Hometown」という3つの変数が空宣言されたとみなされるので、出力結果は全部「nil」になってしまいます。C++のクラスは、自分の持っているメンバにアクセスするためにメソッド呼び出し時に暗黙的に「thisポインタ」を渡しています。このthisに相当するものが必要なんです。Data.New();obj1.print(obj1);一番下のコードでobj1テーブルが持つprint関数に自分自身を渡しています。自分の持っている値を自分の持っている関数に処理してもらっているわけで、これは嬉しいことに成功します。Hometownが正しく出力されます。C++の場合も実はメソッドには暗黙的にthisが渡されているのですが、それをLua側で明示的に渡してあげればいいんです。...呼び出す時に毎回自分の変数名を入れるのはちょっと冗長な感じもします。そのため、Luaでは「テーブルに登録した関数を呼び出すときに『:』を使うと、テーブル自体を第1引数に渡す」というシンタックスシュガーがあるんです。Data.New();obj1:print();先との違いがわかりますでしょうか?print関数の呼び出しにコンマ(.)の替りにコロン(:)を使っています。これでprint関数の第1引数に暗黙的にobj1自身が渡されるんです。これは正にC++のメソッドを呼び出した時と同じ挙動です。これでメソッドも定義できました。Lua側でクラスを宣言するかのようなNew関数を作れば、わりと簡単にクラスっぽい事ができるわけです。クラスっぽい部分だけを外部ファイルに置いて呼び出すクラスっぽいことはできるようになったわけですが、毎回これをLuaファイルに書くのはもちろんシンドイわけです。外部ファイルにこの宣言部分だけを記述して、別のLuaファイルではそれを呼び出して使えるようにすると便利です。C言語でいう「#include」が欲しいというわけです。Luaには「require」というC言語の#includeに相当するライブラリ関数があります。Data.New();obj1:print();ファイル名を指定するのですが「拡張子をつけない」事に注意して下さい。付けると別挙動になってしまいます。これでこの関数が呼び出された時にClassData.luaがLuaステートにより実行・登録されます。これでコードの再利用がどんどんできるようになるわけです。同じLuaステートで同じファイルがrequireされる度にコードが走ります。これは大量のLuaファイルを扱うときに死活問題となります。IKD_OX_DATA_H...#endifと重複インクルードを避けています。{...};}という対処が必要になるかもしれません。Data.New();obj1:print();Luaのテーブル機能はこういう幅広い機能拡張を作ることができ、大変面白い仕組みだと思います。これとC++側をどうリンクさせていけば良いのか。次はその辺りを考えてみます。