ルアのクラス、またはコロンを取り除く

誰もが知っているように、luaにはそのようなクラスやオブジェクトはありません。 ただし、メタテーブルと構文糖があります。

これらのメカニズムを使用すると、クラスの類似性を実装するのに十分簡単です。

結果は次のようになります。

最も簡単なクラス
local MyClass = {} -- the table representing the class, which will double as the metatable for the instances MyClass.__index = MyClass -- failed table lookups on the instances should fallback to the class table, to get methods -- syntax equivalent to "MyClass.new = function..." function MyClass.new(init) local self = setmetatable({}, MyClass) self.value = init return self end function MyClass.set_value(self, newval) self.value = newval end function MyClass.get_value(self) return self.value end local i = MyClass.new(5) -- tbl:name(arg) is a shortcut for tbl.name(tbl, arg), except tbl is evaluated only once print(i:get_value()) --> 5 i:set_value(6) print(i:get_value()) --> 6
      
      





lua-users.org/wiki/ObjectOrientationTutorialから取得



もちろん、これはすべて良いことです。特定の器用さを備えていても、継承を実現できます。

しかし、パブリッククラスとプライベートクラスのメンバーはどこにいますか? 実際、この例ではすべて公開されています。 はい、コロンの使用場所を覚えておく必要があります。

 MyClass:myFunc()
      
      





そして、ほんの一点だけです:

 MyClass.myOtherFunc()
      
      





そして、クラスの静的メンバー? 本当に拒否する必要がありますか?





だから私は拒否したくなかったし、集団農場を始めた...



それで、私はあなたに私の集合農場を紹介します:

私の集団農場
 createClass = function() local creator = {} creator.__private = { object_class = {}, } creator.__oncall = function(class_creator) -- Get the class definition so we can make needed variables private, static, etc. local this = class_creator() -- Initialize class from class definition __init = function() -- Init Public Static local class = {} if (type(this.__public_static) == "table") then class = this.__public_static end -- Init Object local thisClass = this local __constructor = function(...) local object = {} local this = class_creator() -- Init Public if (type(this.__public) == "table") then object = this.__public end -- Init static values of the class this.__public_static = thisClass.__public_static this.__private_static = thisClass.__private_static -- Call Constructor if (type(this.__construct) == "function") then this.__construct(...) end -- Returning constructed object return object end return {class = class, constructor = __constructor} end -- Creating class (returning constructor) local class_data = __init() local class = class_data.class local constructor = class_data.constructor -- Set class metatable (with setting constructor) local class_metatable = { __newindex = function(t, key, value) if type(t[key])=="nil" or type(t[key])=="function" then error("Attempt to redefine class") end rawset(t, key, value) end, __metatable = false, __call = function(t, ...) if type(t) == nil then error("Class object create failed!") end local obj = constructor(...) creator.__private.object_class[obj] = t local object_metatable = { __newindex = function(t, key, value) class = creator.__private.object_class[t] if type(class[key])~="nil" and type(class[key])~="function" then rawset(class, key, value) return end if type(t[key])~="nil" and type(t[key])~="function" then rawset(t, key, value) return end error("Attempt to redefine object") end, __index = t, __metatable = false, } setmetatable(obj, object_metatable) return obj end, } -- Setting class metatable to the class itself setmetatable(class, class_metatable) -- Returning resulting class return class end return creator.__oncall end createClass = createClass()
      
      









そして、それを使用する方法は? 非常に簡単です、ここにあなたのためのテンプレートがあります:

 myclass_prototype = function() local this = {} this.__public_static = { -- Public Static Variables statvalue = 5, -- Public Static Funcs statfunc = function() print(this.__public_static.statvalue) end, } this.__private_static = { -- Private Static Variables privstatdat = 2, -- Private Static Funcs privstatfunc = function() print(this.__private_static.privstatdat) end, } this.__public = { -- Public Variables pubdata = 3, -- Public Funcs pubfunc = function(newprivate) print(this.__public.pubdata) this.__private.privdata = newprivate end, } this.__private = { -- Private Variables privdata = 1, -- Private Funcs listallprivate = function() print(this.__private.privdata) end, } this.__construct = function() -- Constructor end return this end myclass=createClass(myclass_prototype)
      
      





ご覧のとおり、クラス内から呼び出すたびに、「this .__ private.privdata」のパスを毎回指定する必要がありますが、作成したクラスの使用例を次に示します。

 myobject = myclass() myobject.pubfunc(999)
      
      





このコードが呼び出されると、myclassクラスからmyobjectオブジェクトが作成され、pubfunc関数が呼び出されます。これにより、パブリック変数の内容が強調表示され、プライベート変数が変更されます。

そして、コロンの問題はありません!

ところで、静的呼び出しも機能します。 クラスとオブジェクトの両方から。



そこで、ここでどのような魔法が起こるかを簡単に説明します。 そして、ここでいわゆるアップバリューとジャグリングがあります。 アップバリューは、内部からは見えるが外部からは見えない変数です! プライベートに非常に似ていますよね?

そのため、「プロトタイプ」関数を作成した後、新しいスコープを作成し、クラスのすべての内部をそのクラスに配置し、クラスのパブリックおよびパブリック静的メンバーのみを取り出しました。 そして、残りの魔法はメタテーブルによって実行され、クラス/オブジェクトを表す外部テーブルの「存在しない」メンバーをリクエストしたときに何が起こるかを正確に決定できます。

混乱しているように聞こえますが、説明はできません-特別ではありません:)



私は長い間、そのようなシステムで継承を行う方法を考えましたが、私はそれを思いつきませんでした-アップバリューは私たちの行動を真剣に制限し、デバッグライブラリのような倒錯を使用したくありませんでした-それは常に含まれていません。 誰もがそれを考えるなら、私は見てうれしいです!



PS:私の投稿が誰かにとって明白なものである場合-それで、私は自分自身を過大評価しています:)厳密に判断しないでください。



All Articles