Luaはオブジェクト向けメカニズムを実現

3785 ワード

くだらない話を始める
最近Luaを拾い直しました.新しいプロジェクトが使われているからです.4~5年ほど前にゲーム業界に入ろうとしたとき、ある会社の募集要項にLuaが載っているのを見て、夏休みの時間を借りて『Luaプログラミング(第2版)』を読み終えた.最初の頃、交換変数が1つの文で実現されているのを見て何だか興奮していたのを覚えていますが、当初は毛が興奮していたのは今でも分かりませんでした....本の中でLua言語について詳しく述べ、その柔軟性を強調したが、当時は理解していたような状態で、何の体得もなかった.しばらく仕事をしてから手に取ると、確かに共感して、今ではこのコンパクトなLuaがますます好きになりました.Luaの美しさは、他の言語ほど豊富な特性を提供しないが、これらの特性を実現するメカニズムを提供していることにある.今日はMetTableを利用してLuaにオブジェクト向けのプロパティを追加します.始まる前に興奮した行のコードを書きます~~
a, b = b, a

1コード
1.1 OO特性実装
ここでの実現は雲風大神から参考にして、簡略化して生まれた(Wiki原文).個人の資質が限られているため、やや複雑な案を理解するのは難しい.原版コードは短いが、理解に時間がかかった.後で使いやすいように、自分の考え方によって、この版を出して、比較的に理解しやすいと思っています.
--          
local _ClzTbl = {}

--          
local _BaseMeta = { __index = function(childClz, k)
    if not childClz.base then return nil end
    --    :1
    --              ,           (       )
    local v = childClz.base[k]
    childClz[k] = v
    return v;
end }

---      
---   :        Ctor
---   :       base,           MetaTable.
---@param clzName string   ,            
---@param base table       ,      
function class(clzName, base)
    if type(clzName) ~= 'string' then return nil end
    local clz = _ClzTbl[clzName]
    --          ,    
    --       ,     DoFile      
    if clz then return clz end
    clz = {
        Ctor = false,
        base = base,
    }
    if base then
        setmetatable(clz, _BaseMeta)
    end
    _ClzTbl[clzName] = clz
    return clz
end

---   :2
---        
---          ,      
local _Create
_Create = function(clz, obj, ...)
    if clz.base then
        _Create(clz.base, obj, ...)
    end
    if clz.Ctor then
        clz.Ctor(obj, ...)
    end
end

---     
---@param clz table       ,      table         
---@param ...              
function new(clz, ...)
    if type(clz) == 'string' then
        clz = _ClzTbl[clz]
    end
    if not clz then return nil end
    local obj = {}
    setmetatable(obj, { __index = clz })
    _Create(clz, obj, ...)
    return obj
end

1.2例
-- 1.   
Base = class('Base')
function Base:Ctor(name)
    self._name= name
    print('This is Base....')
end

Child = class('Child', Base)
function Child:Ctor(name)
    print('Old name:' .. self.__name)
    self._name = name
    print('New name:' .. self.__name)
end

-- 2.    (        )
child1 = new (Child, 'Walker')
child2 = new ('Child', 'Walker')

2概要
ここで実現したのは、C#という自身がOOをサポートする言語の使用習慣を踏襲し、Pythonの影もある.Luaではクラス、オブジェクトに何の違いもなく、tableです.概念的に明確にするために、classはクラス構造を定義するために使用され、newはオブジェクトを作成するために使用される.
2.1 class
クラス構造としてTable,すなわちオブジェクトのテンプレートを生成する.
  • クラスに直接定義メンバー(関数、変数)は、すべてのオブジェクト間で共有(ここではPythonと同様)
  • である.
  • クラス構造ではbase変数でベースクラス構造を参照し,単一継承を実現した.
  • 通過_indexメタメソッドにより、効率的なベースクラスメンバー検索(継承)
  • を実現
    2.2 new(オブジェクト)
  • 直接メタテーブルでオブジェクト構造の作成
  • を完了する.
  • _CreateはC#のオブジェクト構築順序(ベースクラス->サブクラス)
  • を実現した.
  • コンストラクション関数Ctorでselfに付与される変数こそ、メンバー変数(Python方式)である.もちろん動的言語の特性のため,任意の位置でselfに値を割り当てることは有効である.

  • 3変種
    注意深い友达は発見したかもしれませんが、実装コードには2つの変種点がマークされています.このバージョンのコード実装の特性は雲風大神の基本と一致しており、より理解しやすい方法で再構築された(少なくとも私自身には理解しやすい)ことに相当する.ちなみに、現在のプロジェクトで使われているのは雲風大神の原版です.再構築が完了してから見ると、この2つは異なる方法で、他の状況や使い方をサポートできることがわかります.
    3.1変種点1
    変種点1は、ベースクラスメンバーが呼び出されると、そのメンバーがサブクラスのTableにコピーされる.この方式は二次検索の効率を向上させ,特に継承階層が深い場合である.これは、メモリリソースがCPUリソースよりも希少である場合に適切ではない空間的に時間を変えるスキームです.そして通常は継承階層があまり深くないので、Luaでは3層を超えて継承されていると思いますが、設計上問題がある可能性が高いと思います.ここの修正方法はとても簡単で、直接_index=baseでいいです.(ファイルは10行短くできます)
    3.2変種点2
    _Createが実装するオブジェクト構造階層は、最上位レベルのベースクラスから現在のサブクラスに順次呼び出されます.これはC#のような言語で使用される方法です.後にPythonの方式を考えると,ベースクラスの構造を歩くかどうかはサブクラスによって決まる.クラス構造にbaseが記録され、削除されました.Createが直接Ctorを呼び出すのがPython方式です.(ファイルはまた10行以上短くなりましたOrz....)
    見落としをよく知っているので,指摘を歓迎する.