3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

luaでオブジェクト指向

この記事はアドカレに参加しています。

この記事で紹介しているのはlua5.1についてです。

オブジェクト指向

 オブジェクト指向という考え方の根幹は、「楽をしたい」です。

例えば、以下のようなコードを見てみましょう。

local a1,a2=0,0
local b1,b2=1,2

local c1=a1+b1
local c2=a2+b2

abで足し算をしていますね。1とか2とかでこんがらがってしまいます。足し算の式も二つもあって分かりづらいです。

行列で書くと、

\begin{align}
\begin{bmatrix} c1 \\ c2 \end{bmatrix}
&=
\begin{bmatrix} a1 \\ a2 \end{bmatrix}
+
\begin{bmatrix} b1 \\ b2 \end{bmatrix} \\
C&=A+B
\end{align}

のようになるので、できれば行列のように一回の足し算で終わらせたいです。

luaでこのような楽をするにはメタテーブルというものを使用します。自分で予めオブジェクト同士の演算方法を定義しておくことで、上記のプログラムは次のように書き直すことができます。

local A=new_vec(0,0)
local B=new_vec(1,2)

local C=A+B

一回の足し算で済むので楽でいいですね、

メタテーブルの基本

 luaでいうメタテーブルというのは変数やオブジェクトの持つ特性のことです。+-といった記号があった際にどんな演算をするのか、==のような比較演算子がある際にはどのように比較するかなど、メタテーブルは変数やオブジェクトの振る舞いを決めます。

メタテーブルのプログラム

 メタテーブルのプログラムについてみていきましょう。

メタテーブルの最低限

 自分で新しいメタテーブルを作成するには、まずメタテーブルを表すオブジェクトを一つ用意します。

local vec={}

 次に、メタテーブル名.__indexという名前で、定義したメタテーブルを持つオブジェクトが呼び出されたときに返す値を決めます。

function vec.__index(p,key) return key=="x" and p[1] or p[2] end

上記のコードの場合には、メタテーブルvecを持つオブジェクトaで、a.xとしたときにはa[1]の値を返します。また、a.ya.sampleのようにx以外の値で呼び出された際にはa[2]を返します。

オブジェクトにメタテーブルを持たせる

 オブジェクトにメタテーブルを持たせるにはsetmetatable関数を使用します。第一引数にオブジェクトを、第二引数にメタテーブルの名前を指定することで、返り値としてメタテーブルを持ったオブジェクトがきます。

local a={0,0}
local b=setmetatable(a,vec)

 setmetatableのラッパーとして以下のような関数を定義しておくと、簡単にメタテーブルを持ったオブジェクトを作成することができます。

local function new_vec(x,y)
 local a={x,y}
 return setmetatable(a,vec)
end

演算の定義

 メタテーブルを持ったオブジェクトの演算を定義することができます。定義することのできる演算一覧はこちらを確認してください。

以下にメタテーブルvecでの足し算の定義の仕方を示します。vec.__addの引数は二つありますが、片方はメタテーブルvecを持っていない可能性があるのでtcheckでメタテーブルvecを持っているのかを確認し、メタテーブルを持っていない場合には新しいオブジェクトとして定義しておきます。

local function tcheck(a)
  return getmetatable(a)==vec and "vec" or type(a)
end

local function chengeVec(a)
  return tcheck(a)=="vec" and a or new_vec(a,a)
end


function vec.__add(a,b)
  a,b=chengeVec(a),chengeVec(b)
  --xyそれぞれの要素で足し算する
  return new_vec(a.x+b.x,a.y+b.y)
end

プログラム例

 xyでそれぞれ四則演算をするようなメタテーブルを以下に示します。

local vec={}

local function new_vec(x,y)
  local a={x,y}
  return setmetatable(a,vec)
end

local function tcheck(a) return getmetatable(a)==vec and "vec" or type(a) end

local function chengeVec(a) return tcheck(a)=="vec" and a or new_vec(a,a) end

function vec.__index(p,key) return key=="x" and p[1] or p[2] end

function vec.__add(a,b)
  a,b=chengeVec(a),chengeVec(b)
  return new_vec(a.x+b.x,a.y+b.y)
end

function vec.__sub(a,b)
  a,b=chengeVec(a),chengeVec(b)
  return new_vec(a.x-b.x,a.y-b.y)
end

function vec.__mul(a,b)
  a,b=chengeVec(a),chengeVec(b)
  return new_vec(a.x*b.x,a.y*b.y)
end

function vec.__div(a,b)
  a,b=chengeVec(a),chengeVec(b)
  return new_vec(a.x/b.x,a.y/b.y)
end

      
使用例です。

local x1,x2,d=new_vec(1,2),new_vec(3,4)

d=x1+x2
debug_print("test add : "..d.x.." : "..d.y)
--test add : 4 : 6

d=x1-x2
debug_print("test sub : "..d.x.." : "..d.y)
--test sub : -2 : -2

d=3*x2
debug_print("test mul : "..d.x.." : "..d.y)
--test mul : 9 : 12

参考文献

Lua 5.1 Reference Manual
第 4 回: Lua のオブジェクト指向について紹介する
luaのメソッドで ":" を避ける(lua scriptとc++両方)

むすび

 メタテーブルを使用したプログラムというのは、メタテーブルを使用してないプログラムよりも遅いらしいです。僕はluaを即時実行できるスクリプト言語として用いることが多いので、c++互換になるような書き方ができるだけでも嬉しいんですけどね。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?