【Lua】対象解析
6546 ワード
前に書く
lua自体が継承をサポートしていないことを知っています.luaのすべてのオブジェクトはtableで構成されています.ここでは、メタテーブルを使用してクラスの継承をシミュレートできることを知っています.コアインプリメンテーションは_indexメタメソッド.簡単な実装は次のとおりです.
単純パッケージ
まず、簡単なパッケージ継承方法を見てみましょう.
ここでは簡単なベースクラスを実現し,値を伝達できる簡単な構造方法を実現した.しかし、個人的にはこの構造方法を使うのはよくないと思います.むしろ、直接方法を書いて外に初期化方法を書いたほうがいいと思います.
middleclassパッケージ
これはgithubの上で誰かが与えたlua継承の方案で、特徴は簡単で実用的です.githubアドレス、使用するバージョンは4.1です.
簡単な使用例:
出力:
これは公式に与えられた例です.とても簡単で分かりやすいです.公式のチュートリアルもあります
解析:
私たちはclass('Person')という文から解析を始めました.ちょうど彼の仕事の流れを見ることができます.
ここで呼び出された_callメタメソッド、メタメソッドで呼び出されたmiddleclass.class(...),クラスのテーブルを生成します.
middleclass.class(...)で呼び出された継承されたクラスsuper:subcalssと個別のクラスを生成する_includeMixin(_createClass(name), DefaultMixin),
_createClass(name)この方法は、クラスの基本構造を作成するために使用されるか、抽象クラスとして理解できる.
属性は次のとおりです. nameクラス名 super親のtable static静的テーブル __instanceDictはクラス定義の属性と関数(親を含む) を格納します. __decaredMethod(親を除く現在のクラス宣言方法) subclassesサブクラステーブル、弱参照 を使用
まずaClassを設定します.staticテーブルのメタテーブルは_index = __instanceDict(またはsuper.static)を設定し、aClassメタテーブル_を設定します.indexはstaticおよび_tostringと_callメタメソッド.ここの__callメタメソッドの場合に呼び出されるクラスのnewメソッド.
使用_includeMixinこの方法は私たちのクラスに具体的な充填をします.ここではDefaultMixinのテーブルを使用します.このテーブルは、上に構築した抽象クラスを実現するために理解することができます.DefaultMixinでは、次の方法があります. __tostring:デフォルトtostringメソッド initialize:初期化方法はデフォルトのコンストラクション関数 に似ています. isInstanceOf:クラスのインスタンス静的メソッドであるかどうかを判断する allocate:インスタンステーブルaを作成する.class属性を追加し、クラステーブルb.クラステーブルの__を指すinstanceDictはメタテーブル に設定されている
●new:allocateメソッドとinitializeメソッドを呼び出し、インスタンスがオブジェクトを出て構築メソッドを呼び出します.●subclass:サブクラスの作成
●isSubclassOf:指定されたクラスのサブクラスかどうか.●include:このクラスにパラメータを結合して呼び出した_includeMixinメソッド.
_includeMixin:このメソッドを使用して、埋め込み前に構築された抽象クラスを、静的および非静的のメソッドとパラメータをそれぞれ抽象クラスに割り当てます.
_declareInstanceMethod:クラスに宣言メソッドと属性を追加するへの登録先_declaredMethods fがnilの場合、親に行ってフィールド を取得するドメインをサブクラスに追加 _propagateInstanceMethod:ドメインをテーブルに追加し、継承に相当するすべてのサブクラスに追加 name=_の場合index、呼び出し_createIndexWrapper aClass._にfを追加instanceDict[name]中 すべてのサブクラスを巡回し、サブクラスにメソッドが含まれていない場合は、サブクラスに追加する(含まれている場合は書き換えに相当する) .
_createIndexWrapper:はい_index処理
まとめ __instanceDictは、現在のクラス、およびすべての親定義のインスタンスメソッド(プロパティ),を記録します.indexは自分を指す __declaredMethods現在のクラス宣言を記録する方法(属性) subclasses現在のクラスのすべてのサブクラス、弱参照 static静的テーブル、new、include、isSubclassOfなどのメソッドを定義します.index指向_instanceDict. インスタンス変数はstaticテーブルに直接アクセスできません.通過する必要があります.class.staticアクセス.クラスの静的メソッドはclass.static:func を定義するクラスのデフォルトテーブル定義_instanceDict,__declaredMethods,staticなどのプロパティ._indexはstaticテーブルを指し、staticのフィールド(A:new()を直接使用できます._新Indexは_declareInstanceMethodメソッド、フィールドを追加すると更新されます_instanceDictおよび_declareMethods インスタンステーブルはclassプロパティを定義し、現在のクラスを指します.metatableは対応クラスの_instanceDict
lua自体が継承をサポートしていないことを知っています.luaのすべてのオブジェクトはtableで構成されています.ここでは、メタテーブルを使用してクラスの継承をシミュレートできることを知っています.コアインプリメンテーションは_indexメタメソッド.簡単な実装は次のとおりです.
Super={} --
SubClass={} --
setmetatable(SubClass,{__index=Super}) --
単純パッケージ
まず、簡単なパッケージ継承方法を見てみましょう.
BaseObject = {}
BaseObject .__index = BaseObject
function BaseObject:New(object,...)
object = object or {}
setmetatable(object, self)
self.__index = self
if object.Ctor then
object:Ctor(...)
end
return object
end
ここでは簡単なベースクラスを実現し,値を伝達できる簡単な構造方法を実現した.しかし、個人的にはこの構造方法を使うのはよくないと思います.むしろ、直接方法を書いて外に初期化方法を書いたほうがいいと思います.
middleclassパッケージ
これはgithubの上で誰かが与えたlua継承の方案で、特徴は簡単で実用的です.githubアドレス、使用するバージョンは4.1です.
簡単な使用例:
local class = require 'middleclass'
Person = class('Person') -- Person
function Person:initialize(name)
self.name = name
end
function Person:speak()
print('Hi, I am ' .. self.name ..'.')
end
AgedPerson = class('AgedPerson', Person) -- Person AgedPerson
AgedPerson.static.ADULT_AGE = 18 --
function AgedPerson:initialize(name, age)
Person.initialize(self, name) --
self.age = age
end
function AgedPerson:speak()
Person.speak(self) -- "Hi, I am xx."
if(self.age < AgedPerson.ADULT_AGE) then --
print('I am underaged.')
else
print('I am an adult.')
end
end
local p1 = AgedPerson:new('Billy the Kid', 13) --
local p2 = AgedPerson:new('Luke Skywalker', 21)
p1:speak()
p2:speak()
出力:
Hi, I'm Billy the Kid.
I am underaged.
Hi, I'm Luke Skywalker.
I am an adult.
これは公式に与えられた例です.とても簡単で分かりやすいです.公式のチュートリアルもあります
解析:
私たちはclass('Person')という文から解析を始めました.ちょうど彼の仕事の流れを見ることができます.
ここで呼び出された_callメタメソッド、メタメソッドで呼び出されたmiddleclass.class(...),クラスのテーブルを生成します.
setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
middleclass.class(...)で呼び出された継承されたクラスsuper:subcalssと個別のクラスを生成する_includeMixin(_createClass(name), DefaultMixin),
_createClass(name)この方法は、クラスの基本構造を作成するために使用されるか、抽象クラスとして理解できる.
local aClass = { name = name, super = super, static = {},
__instanceDict = dict, __declaredMethods = {},
subclasses = setmetatable({}, {__mode='k'}) }
属性は次のとおりです.
まずaClassを設定します.staticテーブルのメタテーブルは_index = __instanceDict(またはsuper.static)を設定し、aClassメタテーブル_を設定します.indexはstaticおよび_tostringと_callメタメソッド.ここの__callメタメソッドの場合に呼び出されるクラスのnewメソッド.
if super then
setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) or super.static[k] end })
else
setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
end
setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,__call = _call, __newindex = _declareInstanceMethod })
使用_includeMixinこの方法は私たちのクラスに具体的な充填をします.ここではDefaultMixinのテーブルを使用します.このテーブルは、上に構築した抽象クラスを実現するために理解することができます.DefaultMixinでは、次の方法があります.
allocate = function(self)
assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
return setmetatable({ class = self }, self.__instanceDict)
end,
●new:allocateメソッドとinitializeメソッドを呼び出し、インスタンスがオブジェクトを出て構築メソッドを呼び出します.●subclass:サブクラスの作成
subclass = function(self, name)
assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
assert(type(name) == "string", "You must provide a name(string) for your class")
local subclass = _createClass(name, self)// 。
// _propagateInstanceMethod 。
for methodName, f in pairs(self.__instanceDict) do
_propagateInstanceMethod(subclass, methodName, f)
end
// 。
subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
// subclass ,
self.subclasses[subclass] = true
// subclassed ,
self:subclassed(subclass)
return subclass
end
●isSubclassOf:指定されたクラスのサブクラスかどうか.●include:このクラスにパラメータを結合して呼び出した_includeMixinメソッド.
_includeMixin:このメソッドを使用して、埋め込み前に構築された抽象クラスを、静的および非静的のメソッドとパラメータをそれぞれ抽象クラスに割り当てます.
_declareInstanceMethod:クラスに宣言メソッドと属性を追加する
local function _declareInstanceMethod(aClass, name, f)
aClass.__declaredMethods[name] = f
if f == nil and aClass.super then
f = aClass.super.__instanceDict[name]
end
_propagateInstanceMethod(aClass, name, f)
end
local function _propagateInstanceMethod(aClass, name, f)
f = name == "__index" and _createIndexWrapper(aClass, f) or f
aClass.__instanceDict[name] = f
for subclass in pairs(aClass.subclasses) do
if rawget(subclass.__declaredMethods, name) == nil then
_propagateInstanceMethod(subclass, name, f)
end
end
end
_createIndexWrapper:はい_index処理
まとめ