Lua でテーブルを使ったコード書いてると、しばしば、
「特定のフィールドを予め確保しておきたい」状況に出くわします。
例えば __index や __newindex をカスタマイズした場合に、
それらを無視してフィールドにアクセスする場合、普通は rawget/rawset を使うわけですが、
インデックスアクセスと rawget/rawset は、どちらが高速か? - 野良C++erの雑記帳で書いたように、
実は rawset/rawget をするより、普通にテーブルアクセスしたほうが高速らしいのです。
またそれ以外にも、テーブルの配列部分に「穴」があるといろいろ問題があったり、
とにかく、 nil という値は Lua の中で特別扱いされすぎていて、若干使いにくいです。
じゃあ nil じゃなくて false を使えばいいじゃないか、とも考えましたが、
確かに if not x とか書けるので混乱は少ないので悪くないですが、
やはり論理値は論理演算の結果であるという意味的に、どうなのかな、と。
で、そういう場合に、一意なタグがあると便利だな、ということで、
一意なタグを生成する関数 generate_tag なんてもんを作ってみました:
http://ideone.com/gvyJ8
-- 一意なタグを作る do -- メタテーブル local mt do local error = error local function index_error() error( "attempt to index a tag", 2 ) end mt = { __index = index_error, __newindex = index_error, __metatable = "tag" } end -- 本体 local setmetatable = setmetatable function generate_tag() local t = {} setmetatable( t, mt ) return t end end local none = generate_tag() t = { none } print( #t ) -- 1 print( t[1] == none ) -- true -- error! none.a = x
だから何。
追記
C API を使っていいなら、
int generate_tag( lua_State* L ) { lua_newuserdata( L, 1 ); return 1; }
これでおっけーです。無駄なテーブルとか必要ないので省メモリですね!