Lua学習ノート:対象向け

3379 ワード

Luaにはテーブル(Table)という唯一のデータ構造しか存在しないが,オブジェクト向けの概念を遊ぶことができる.
メンバー関数の追加
よし、C++に詳しいなら似たような進化過程をよく理解する:structに関数を追加できるのはCからC++に移行する第一認識だとすれば、Tableに関数を追加することはLuaがどのようにオブジェクトに向かっているかを認識する第一歩と言えるだろう.

player = { health = 200 }  -->       player  ,         
function takeDamage(self, amount)
  self.health = self.health - amount
end

takeDamage(player, 20)  -->   


独立したtakeDamageplayerに詰め込むにはどうすればいいですか?答えは直接定義されています.

player = { health = 200 }
function player.takeDamage(self, amount)
  self.health = self.health - amount
end

player.takeDamage(player, 20)  -->   


これは、playerテーブルにtakeDamageというフィールドを追加したことに相当します.次のコードと同じです.

player = {
  health = 200,
  takeDamage = function(self, amount)  --> Lua       first-class value
    self.health = self.health - amount
  end
}

player.takeDamage(player, 20)  -->   


呼び出し時のplayer.takeDamage(player,20)はやや違和感があり(DRYという用語が使われているそうです)、「コロンオペレータ」という専門的な文法糖が出動します.

player:takeDamage(20)              -->     player.takeDamage(player, 20)
function player:takeDamage(amount) -->     function player.takeDamage(self, amount)


オブジェクトからクラスに昇華
クラスの意味は,1つのオブジェクトの共通点を抽出して量産を実現することである(私はでたらめを言っている><).同様にClass概念を持つJavascriptはprototypeを用いてオブジェクト向けを実現し,LuaはMetableによりprototypeと同様の機能を実現する.

Player = {}

function Player:create(o)    -->    o       
  o = o or { health = 200 }  --> Lua   or      ||   ,    nil       nil  
  setmetatable(o, self)
  self.__index = self
  return o
end

function Player:takeDamage(amount)
  self.health = self.health - amount
end

playerA = Player:create()  -->    o   nil
playerB = Player:create()

playerA:takeDamage(20)
playerB:takeDamage(40)


名前の通りMettableもTableであり、metamethodと呼ばれる関数を格納することで、デフォルトの評価動作(文字列として表示する方法、加算方法、接続方法、インデックス方法)を変更できます.Metableの__indexドメインには「インデックスをどうするか」というメソッドが設定されています.たとえば、foo.barが呼び出された場合、foobarというドメインが見つからない場合、Metable:__index(foo,bar)が呼び出されます.次のようになります.

playerA:takeDamage(20)

playerAにはtakeDamgeの関数が存在しないため、Mettableに助けを求める.

getmetatable(playerA).__index.takeDamage(playerA, 20)


Mettableを持ち込んだ後:

Player.__index.takeDamage(playerA, 20)

Player__indexcreateselfに指定されているので、最終的には:

Player.takeDamage(playerA, 20)


そして、takeDamageselfは、正しい対象playerAを得る.
継承
継承はオブジェクト向けの大きな特性であり、どのように「クラス」を作成するかが分かったので、継承も明らかになりました.大明湖畔のパラメータoを覚えていますか.

RMBPlayer = Player:create()
function RMBPlayer:broadcast(message)  -->          
  print(message)
end
function RMBPlayer:takeDamage(amount)  -->         
  self.health = self.health - amount / (self.money / 100)
end

vip = RMBPlayer:create { money = 200 } -->        (   Table           )

vip:takeDamage(20)
vip:broadcast("F*ck")


以上がLuaにおけるオブジェクト指向の実現の基本手法である.