Read an article on the internet about Lua object-oriented files, it is very important, so the focus is extracted. Original in http://blog.csdn.net/guang11cheng/article/details/7547253
meta-table Concepts
In Lua, the alignment is implemented using a meta-table mechanism. MetaTable is a very "Taoist" mechanism, very deep, very powerful, there are some basic concepts more difficult to understand thoroughly. However, only by fully understanding the meta-table can you use Lua's object-oriented objects so that you can be comfortable with writing the advanced syntax of LUA code.
First, in general, a table and its meta-tables are different individuals (not part of the same table), and the meta-table is not created automatically when a new table is created. However, any table can have a meta-table (this ability is present). e.g. T = {} print (Getmetatable (t))-nil, now table T has no meta-table t0 = {} setmetatable (T, t0)--hooks up a meta table assert (getmetatable (t) = = T0)--table t has a meta-table, for T0 t1 = {} setmetatable (T, T1)--For a meta-table, OK assert (getmetatable (t) = T1)--the meta representation of table T is T1 setmetat Able (T, nil)--get rid of table T's meta table, OK print (getmetatable (t))-nil, now table T has no meta table setmetatable (table 1, table 2) Hook table 2 to table 1 of the meta-table, and returns the attached table 1.
The __metatable field in the meta table is used to hide and protect the meta table. When a table is hooked up with an assigned __metatable, the table will return the value of the __metatable field instead of the meta table, using the getmetatable operation. Using setmetatable to manipulate the table (that is, to give the table a new metatable), an error is raised. e.g. t2 = {} T3 = {__metatable = t2} T4 = {} setmetatable (T4, T3) assert (getmetatable (t4) = = t2)--table T4 's meta table is not T3, but T3 The value of __metatable t5 = {} setmetatable (T4, T5)--modifies the T4 's meta-table, error, because T4 in the meta-table has an error in the __metatable field as follows: Lua:test.lua:23:cannot change a Protected metatable Stack traceback: [c]: in function ' setmetatable ' obj.lua:23:in main chunk [C]:? >exit code:1
__index MethodThe __index meta-method in a meta-table is a very powerful meta-method that provides support for backtracking queries (reads). Object-oriented implementations are based on backtracking lookups.
when accessing a field that does not exist in a table, in fact, if the table has a meta-table, this access prompts Lua to look up the __index meta-method in the meta-table. Without this meta-method, the access result is nil. Otherwise, the meta-method is used to provide the final result. __index can be assigned to a function, or it can be a table. is a function, call this function, pass in the parameter (what the argument is), and return several values. is a table, revisit the table in the same way. (When it is a table, the __index is equivalent to the meta-field, the concept is still well-divided, although in Lua everything is a value) Note, this time, there are three of the table of the individual. This piece is very easy to stun, let's take a look at it. The table that we directly manipulate, called Table A, table A, is called Table B, table B's __index field is given the table, called Table C.
The whole process is this, find a field in a, if not found, will go to see a there is no meta-table B, if any, to find the __index field in B has an assignment, the assignment is not a table C, if so, then go to C to find there is no want to access the field, If found, returns the value of the field and returns nil if it is not found. For a table without a meta-table, access a nonexistent field and return a nil directly.
__newindex is a method corresponding to __index, its function is "Update (write)", the two are complementary. The __newindex is not detailed here, but the process is very similar, and the flexible use of two meta-methods can produce many powerful effects.
From the perspective of inheritance characteristics, the initial effect can be achieved using __index.
Object-oriented implementationSome object-oriented languages provide the concept of classes as templates for creating objects. In these languages, an object is an instance of a class. LUA does not have the concept of classes, and each object defines his own behavior and has its own shape. However, it is not difficult to emulate the concept of a class in Lua based on prototype (prototype) language such as self and newtonscript. In these languages, objects do not have classes. Instead, each object has a prototype (prototype), which is first found in prototype when certain operations that are not part of the object are called. In such a language, the implementation of the class (classes) mechanism, we create an object, as a prototype of other objects (the prototype object is a class, the other object is the instance of the class). Classes work in the same way as prototype, which defines the behavior of specific objects. The implementation of the prototype in Lua is simple, and in the three tables analyzed above, C is the prototype of a.
After the principle of speaking, a little bit of skill. In fact, the above-mentioned three tables, it is not necessarily a completely different. A and C can be the same. Look at the following example. A = {} setmetatable (A, {__index = a})
At this time, the equivalent of a is a self-prototype, oneself is a prototype, is a very interesting word. That is, in the search, you can not find it in the other places to find. However, itself is not very much used in its own prototype itself. This is useful if a can be a class, and then a new object is generated that is a prototype of a, which is later discussed.
Again, it can also be its own meta-table. That is, a can be a meta-table. A = {} setmetatable (A, a) can then be written, a.__index = table or function itself is useful for its own meta-table, if A.__index is given a table, at least can produce a table in memory, and if A.__index is a function, Then it will produce very simple and powerful effects. (__index is a field of its own, not very concise)
Then, the meta Table B and the prototype Table C can also be the same. A = {} b = {} B.__index = b setmetatable (A, B) at this point, a table's meta-table is the prototype of the table, which is the class of the table in the object-oriented concept.
We can even write this: a = {} setmetatable (A, a) A.__index = a
From a grammatical principle, it works. But the LUA interpreter, in order to avoid unnecessary trouble (circular definition), this situation to kick off, if this write, will error, and the loop in GetTable
To be honest, such a definition is really useless.
The following begins the formal entry into the object-oriented implementation. First refer to the implementation fragment in Sputnik,
local Sputnik = {}
local Sputnik_mt = {__metatable = {}, __index = Sputnik}
function new(config, logger)
-- 这里生成obj对象之后,obj的原型就是Sputnik了,而后面会有很多的Sputnik的方法定义
local obj = setmetatable({}, Sputnik_mt)
-- 这里的方法就是“继承”的Sputnik的方法
obj:init(config)
返回这个对象的引用
return obj
end
As seen above, two table definitions add a method that implements the class and the schema that the class produces the object from. Because this is in the module, there is no table name in front of new. The benefit of this approach is that when calling this module, use Sputnik = require "Sputnik" and then call S = sputnik.new () to generate a Sputnik object s, This object inherits all the methods and properties of the prototype Sputnik (the table defined above).
However, there is a problem with the definition of this method, that is, the inheritance of the class is not easy to implement. It is only convenient for the definition of the class and the way the object is generated, but it is inconvenient to inherit between classes.
Below, it is implemented in a different way.
A = {balance = 0}
Span class= "KWD" >function A : new ( o ) Span class= "PLN" > -- actually the first parameter of the function is self lua supports omitting the first argument with the colon operator self function A new ( self T Span class= "pun") end "
o = o or {} -- create object if user does not provide one
setmetatable(o, self)
self.__index = self
return o
end
Generate an Object AA from a
AA = A:new ()--when invoked using the same colon operator, omit the first argument self, or you can use the
dot operator
(The dot operator is actually a method of referencing a key in a table as a string element.): AA = A.new (A). The effect of a
colon is equal to the addition of an additional hidden parameter a when function definitions and function calls
At this point, AA is a new table, it is an object, but also a class. It can also continue to do the following: s = aa:new ()
There is no new method in AA, but it is given a meta-table (also a prototype), at this time there is a new method in A,a.AA goes back
through __index to a to find the new method, and executes the new code, and also passes in the self parameter. This is a wonderful place, and this time the self parameter passed in refers to the AA table, not the first time the table is called. So after Aa:new () executes, again, a new object s is generated, and the object is prototyped with a AA and inherits all the contents of AA. At this point, we have not already implemented the inheritance of the class? AA is now a subclass of a, and S is an object instance of AA. You can also create long succession chains later.
As can be seen from the above, the concept of class and prototype is still different, Lua is a prototype language, this is evident, the class in this language is the prototype, and the prototype is just a regular object.
in fact, Lua does not have "classes", only "values", but it provides a chain backtracking mechanism that allows one table A to implicitly access the elements (numbers, functions) of another table Metaa. Metaa can be seen as an "ancestor" of a, hence the meta table called A.
Below, if a function is defined in a:
function A:acc( v )
self.x = self.x + v
end
function A:dec( v )
if v > self.x then error "not more than zero" end
self.x = self.x - v
end
Then, call S:ACC now (5)
Well, that's how it's called,
first find in S if there is no ACC this method, did not find, and then to find a AA in there is no ACC this method, or did not find, go to a in find there is no this method, found. Once found, the self parameter pointing to S and the 5 parameter are passed into the ACC function,and execute the code of ACC, when executing inside code, this sentence: self.x = self.x + V
at the right end of the expression, self.x is a null value, because self now points to s, so, according to __index back, always find an x in a, and then reference this x value,Therefore, the expression above becomes self.x = 10 + 5 to the right of the calculation of 15, assigned to the left, but at this time self.x is not defined, but s (and S of the metatable) also does not define the __newindex meta method, so, in the self (now s) point to the table inside a new X field, Then assign the 15 value to this field.
After this operation, in instance s, there is a field (member variable) x, which has a value of 15. Next time, if you call S:dec (10) Again, you will do a similar backtracking operation, but this time only to do the backtracking of the method, not the member variable x, because there is already x this member variable, after executing this function, s.x will be equal to 5.
In summary, this is the entire class inheritance, and the object instance method reference process. However, the words are not finished. AA as a subclass of a, itself can have some as, because the class and object under AA in the search, will go through it first, will be to its father a there, therefore, it can be overloaded with a method, for example, it can define the following function:
function Aa:acc (v) ... end
function Aa:dec (v) ... end
The function can write some new and different content to deal with the complex differences in the real world. This feature, in object-oriented terms, is that subclasses can override the parent class's methods and member variables (fields), which are overloads. This feature is required.
AA can also define some methods and fields not in a, the operation is the same, here to mention.
The object in Lua has a very flexible and powerful feature, that is, there is no need to create a new class for specifying a new behavior. If only one object requires some special behavior, you can implement this behavior directly in the object. That is, after the object is created, the methods and fields of the object can be added and overloaded to cope with the actual variability. Without having to excuse the modification of the class definition. This is also the benefit of a class being a common object. More flexible.
As you can see, the a:new () function is a critical function that plays a key role in the inheritance of classes. However, in order to accommodate the situation (many) used in the module, a function new (t) a:new (t) end is defined outside function a:new to encapsulate the generated function, and then, just use the module name. New () can generate a real on the outside of the module Example object.
Almost, you can see, this kind of implementation of the mechanism is how self-consistent, concise, flexible, powerful! But it's going to torture your brain. Composite code:--Object A, also a type (object and class is a thing, called a prototype) a = {x = ten, y = 20}
function A:new (o) o = O or {}--Create object if user does not provide one setmetatable (O, self) self.__index = self return o end
function New (o) a:new (o) End
function A:acc (v) self.x = self.x + V End
function A:dec (v) if v > self.x then error ' not more than zero ' end
self.x = Self.x-v End
--produces an object AA from A, also a subtype AA = A:new ()
--Overloaded function Aa:acc (v) self.x = self.x + v print (self.x) end
--new methods in subclasses function Aa:getx () return self.x end
-At this point, AA is a new table, it is an object, but also a class, is a subclass of AA. It can also continue to do the following: s = aa:new ()
--Then, now call S:ACC (5) S:dec (S:getx ()) Print
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////
--integrated Example two
Class = {x = 0}
function Class:new (oo) Local o = oo or {} setmetatable (O, self) self.__index = self return o end
function Class:func1 (a) self.x =--Self is a call to a member variable by a point number return self.x end
function Class:func2 () Local A = SELF:FUNC1 ()--Self is called by a colon member function print (a) end
--Create an object obj1 = Class:new () obj1:func2 ()--the object calls the member function through a colon
--Call member functions by class name CLASS:FUNC2 ()
--Define a subclass ChildClass = Class:new ()
--overriding function functions in the parent class CHILDCLASS:FUNC1 (a) return + END
--Create an object obj2 = Childclass:new () obj2:func2 ()
--Call member functions by class name CHILDCLASS:FUNC2 ()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// Legacy PROBLEM: Global variables are stored in the _g table, where are local variables stored?
is the parameter of the function a local variable? is the variable defined in the function body a local variable?
Return a local variable (such as a table), how is it done?
function f (ABC) Xzy = Xzy or {}PQ = 1
Return ABC end
--print (ABC)--Nil--print (XYZ)--nil--print (PQ)--Nil
For K, V in Pairs (_g) doprint (k) print (v) end
From for notes (Wiz)
Lua Object-oriented