アーカイブ

2009 年 4 月 17 日 のアーカイブ

Luaで演算子オーバーロード

2009 年 4 月 17 日
コメントは受け付けていません。

Luaには、メタテーブルと言う機構があり、テーブルに割り当てることで、演算子オーバーロードが実現できます。

メタテーブルをあらかじめ作成し、指定したテーブルに割り当てを行うことで動作します。

そこで、試しに配列のマージを+演算子でできるようにしてみます。

Array_meta = {
 __add = function(x,y)
 z = {}
 for i=1,#x do
 table.insert(z, x[i])
 end
 for i=1,#y do
 table.insert(z, y[i])
 end
 return z
 end
}
function Array(...)
 local tbl = {...}
 setmetatable(tbl, Array_meta)
 return tbl
end

t1 = Array(1,2,3,4,5,6,7,8,9,10)
t2 = Array(2,4,6,8,10)

t3 = t1+t2
for i=1,#t3 do
 print(string.format("#%02d %d", i, t3[i]))
end

1行目から12行目までが、Array_metaと言う名前でメタテーブルを定義しています。

__add関数が加算演算子(+)の演算子オーバーロード部分です。

この間数内で配列をつなぎ合わせています。

13行目から17行目までが、Array関数の定義です。

PHPのarray関数のように、引数で配列の初期化を行い、テーブルを生成して返します。

15行目が作ったテーブルに対して、Array_metaをメタテーブルとして関連付けしています。

これにより、テーブルへの+演算子がオーバーロードされます。

22行目でテーブルt1とテーブルt2を+記号でつなげています。t3は__add関数が呼ばれた結果が入ります。

メタテーブルには、__add以外にも多くの演算子の定義が可能です。

演算子 メタテーブル関数名
+ __add
- __sub
* __mul
/ __div
% __mod
^ __pow
..(結合演算子) __concat
- (変数前のマイナス記号として) __unm
#(変数前の要素数取得記号として) __len
== __eq
< __lt
<= __le

色々作ってみましょう。

ただし、多用すると記述内容と実際の動作が予想できなくなるなど副作用もあるため、

最低限にしておきましょう。

今回の例でも、配列を行列とみなす場合は、__addよりも__concatを使った方がより分かりやすいのです。

ただし、配列同士を..でつないだ場合は、文字列に変換してつなげる方が嬉しい人もいるでしょう。

この辺の判断が難しいのです・・・

admin プログラム小技 , ,

LuaでDB操作

2009 年 4 月 17 日
コメントは受け付けていません。

Luaでも当然DBにアクセスできます。

LuaSQLというライブラリを使用します。

インストール方法は、Ubuntu8.04であればSynapticからliblua5.1-sql-mysql-2というパッケージを

インストールするだけです。

使い方も簡単です。

MySQLサーバに接続するプログラムを書いてみましょう。

require "luasql.mysql"

dbname = "test"
dbhost = "localhost"
dbuser = "test"
dbpass = ""

env = assert(luasql.mysql())
con = assert(env:connect(dbname, dbuser, dbpass, dbhost))
res = con:execute("DROP TABLE IF EXISTS members")
res = con:execute([[
 CREATE TABLE members(
 id int not null primary key auto_increment,
 name varchar(50) not null,
 regist_dt datetime not null
 )
]])

members = {
 { name="user1" },
 { name="us'er2" }
}

for i, r in ipairs(members) do
 print("name:" .. r.name)
 res = con:execute(string.format([[
 INSERT INTO members(name, regist_dt)
 VALUES('%s', NOW())]], string.gsub(r.name, "'", "''")))
end

cur = con:execute("SELECT id, name, regist_dt from members")
row = cur:fetch({}, "a")
while row do
 print(string.format("#%03d %s (%s)", row.id, row.name, row.regist_dt))
 row = cur:fetch({}, "a")
end

cur:close()
con:close()
env:close()

perlやphpなどのプログラムとほとんど変わりません。
32行や35行で使われているfetch関数の引数は、フェッチ結果を代入するテーブルを指定します。
通常は空のテーブルを指定します。
第2引数は取得した行を配列で取得する(“n”)か、カラム名のハッシュで取得する(“a”)かの指定となります。
引数は2つとも省略可能です。この時は新規にテーブル作成され、配列モード(“n”)で取得されます。

admin プログラム小技 , , ,