入門Luaプログラミング第9章 Luaを拡張してみる(後編)
前回の続き、配列の上限値を設定したりグローバル変数を宣言できなくしたりオブジェクト指向を取り入れてみたり。
配列の上限値を設定する
前回のようにsetmetatable関数でまたしてもメタメソッドを上書きして、添字でアクセスされた場合の動作を書き換える。
> array = { max = 5 } > array.__index = function(table, index) >> if array.max > index then >> return rawget(table, index) >> else >> return nil >> end >> end > array.__newindex = function(table, index, value) >> if array.max > index then >> rawset(table, index, value) >> else >> print("index > array.max") >> end >> end > > list = {} > setmetatable(list, array) > > for i = 1,7 do >> list[i] = i >> print(list[i]) >> end 1 2 3 4 index > array.max nil index > array.max nil index > array.max nil
__indexが"a = b[1]"のような参照されたときに呼ばれるメソッドで、__newindexが"b[1] = 1"のような代入される場合に呼ばれるメソッド。
これらを上書きして5以上の添字の場合、nilを返したり文字を出力したりするようにしている。
だんだんわけのわからないことになってきてるような……
グローバル変数を宣言できないように
上のやつの応用…かな。
> safe = "ok" > global = {} > global.__index = function(table, index) >> print("null : __index") >> end > global.__newindex = function(table, index, value) >> print("null : __newindex") >> end > setmetatable(_G, global) null : __index > a = {} null : __newindex null : __index > b = 1 null : __newindex null : __index > c = '' null : __newindex null : __index > print(safe) ok null : __index
_Gはグローバル変数を保持しているテーブル。_Gの__indexと__newindexを何もしないようにする関数で置き換えてやると、setmetatable関数が呼ばれた後はグローバル変数を宣言しようとしてもできず、それより前に宣言されているものしか使えなくなるという……
まあ、使い方によってはいいかも。
オブジェクト指向を取り入れる
テーブルに関数をくっつけてオブジェクト指向風に?
> cursor = { x = 0, y = 0 } > function cursor:move(x, y) >> cursor.x = x >> cursor.y = y >> end > cursor:move(2, 8) > print(cursor.x) 2 > print(cursor.y) 8
"."でなく":"を使うところがなんとも。どうせなら"::"とかよかったなーなんて。C++風に。
function cursor:move(x, y) -- (略) end
は
function cursor.move(self, x, y) -- (略) end
や
cursor:move = function(x, y) -- (略) end
や
cursor.move = function(self, x, y) -- (略) end
と同じ。まあ一番上が楽かな……
SelfはObjectPascalから持ってきたのかなー。
cursor:move(2, 8)
は
cursor.move(cursor, 2, 8)
と同じ。おとなしく":"を使っておけばいいかな。
結構むずかしかったし、疲れた…… しかも割と量があるという。でもまあそれなりにおもしろかったし、いいか。
クロージャは高階関数のところでやったのでスルー。(本にもさらっと書いてあるだけだし)
これで9章が終わって次回は10章へ。