An object-oriented programming walkthrough in Lua _lua

Source: Internet
Author: User
Tags lua

To put it simply, object-oriented in Lua

The table in Lua is an object that looks at the following simple code:

Copy Code code as follows:

Local TB1 = {A = 1, b = 2}
Local TB2 = {A = 1, b = 2}
Local TB3 = tb1

if tb1 = = Tb2 Then
Print ("TB1 = = TB2")
Else
Print ("Tb1 ~= TB2")
End

tb3.a = 3
Print (tb1.a)

The code above will output TB1 ~= TB2. Shows that two objects of the same worth are two different, while in Lua the table is a reference type. I also concluded in the LUA module and package that we are a module based on table, where functions can be defined in a table, that is, each table object can have its own operations. Read a piece of code:
Copy Code code as follows:

Account = {balance = 0}
function Account.withdraw (v)
Account.balance = Account.balance-v
End

Account.withdraw (10)--Call function
Print (account.balance)

The code above creates a new function and stores the function in the withdraw field of the account object, and then we can call the function. However, using the global name account in a function is a bad programming practice because the function can only work on a particular object, and the particular object must also be stored in a particular global variable. If you change the name of the object, withdraw can no longer work. For example, the following code:

Copy Code code as follows:

A = Account
Account = Nil
A.withdraw (100)

This will cause an error. I'm here to create a new object A with account, which should have no effect on a object when it is assigned to nil. However, an error occurs because account is used internally within the function withdraw instead of variable a. If we modify the Account.balance = Account.balance–v statement inside the withdraw function to: a.balance = A.balance–v, then there is no error. This means that when we need to operate on a function, you need to specify the actual action object, that is, a, which requires an additional argument to represent the operator, just like this in C + +, except that this keyword is replaced with self, and the following code is changed:

Copy Code code as follows:

Account = {balance = 0}
function Account.withdraw (self, v)
Self.balance = Self.balance-v
End

A = Account
Account = Nil
A.withdraw (A, 100)
Print (a.balance)

Then call again, and there will be no errors.

Using the self parameter is a core of all object oriented languages. Most object-oriented languages hide the self parameter from the programmer, which makes it unnecessary for programmers to declare this parameter. Lua can also, when we use a colon to define a function, and then we can hide the parameter, the code above is replaced with a colon, which is the following.

Copy Code code as follows:

Account = {balance = 0}
function Account:withdraw (v)--note here the colon ":"
Self.balance = Self.balance-v
End

A = Account
Account = Nil
A:withdraw (100)-note that the call here also requires a colon ":"
Print (a.balance)

The colon works very simply by adding an extra hidden parameter to the method definition and adding an extra argument to a method call. A colon is just a grammatical convenience and does not introduce anything new; If you want, you can do it without self, instead of manually adding self each time you define a function, as long as you're dealing with self, they're all the same.

Here's a messy talk about something in Lua, mostly saying that table is a different thing and self. The next step is to formally enter the object-oriented world. Don't forget, the things summarized above are very useful.

Class

What is a class? A class is a stencil that creates objects. For example, in C + +, each object is an instance of a particular class. In C + +, if a class is not instantiated, the corresponding operation in this class is basically a bunch of "no use" code, and Lua is not the same, even if you don't instantiate a "class", you can also use the "class" name to call its method directly (for C + +, ignore the static method) This shows that the concept of "class" in Lua differs from the concept of classes in high-level languages such as C + +. There is no concept of a class in Lua, and we all simulate the concept of classes through the existing support of Lua. In Lua, to represent a class, you simply create a prototype (prototype) that is dedicated to other objects. A prototype is also a regular object, which means that we can invoke the corresponding method directly through the prototype. When another object (an instance of a class) encounters an unknown operation, the prototype finds it first.

Implementing prototypes in Lua is very simple, such as having two objects A and B, and having B as a prototype requires only the following code to complete:

Copy Code code as follows:

Setmetatable (A, {__index = b})--It's the meta table, No. See the previous articles about the meta-table: http://www.jb51.net/article/55812.htm

When this code is set, a will look for all operations in B that it does not have. If B is referred to as the "class" of object A, it is merely a change in terminology. Now I start with the simplest, to create an instance object, there must be a prototype, is called "class", look at the following code:
Copy Code code as follows:

Local account = {}--a prototype

Well, now that you have a prototype, how do you use this prototype to create an "instance"? Then look at the following code:

Copy Code code as follows:

function Account:new (o)--this is a colon.
o = O or {}--if the user does not supply a table, create a
Setmetatable (O, self)
Self.__index = Self
Return o
End

Self is equivalent to account when calling Account:new. Next, we can call Account:new to create an instance. Look again:
Copy Code code as follows:

Local A = Account:new{value = 100}--This creates an object a using prototype account
A:display ()

How does this piece of code work? First, a new instance object is created using Account:new, and account is used as the meta table for the new instance object A. And then when we call the A:display function, it's the equivalent of A.display (a), the colon is just a "syntactic sugar", just a convenient way of writing. We created an instance object A, and when we call display, we look for a display field in a and, if not, search for its meta table, so the final invocation is as follows:

Copy Code code as follows:

Getmetatable (a). __index (Display (a))

A's meta table is Account,account's __index is also account. Therefore, the above call can also make this:

Copy Code code as follows:

Account.display (a)

So, what we can actually see is that there is no display method in the instance object a table, but it inherits from the account method, but the self in the display method is definitely a. This allows account (this "class") to define the action. In addition to the method, a also inherits all the fields from account.

Inheritance can be used not only for methods, but also for fields. Therefore, a class can provide not only a method, but also a default value for a field in an instance. Look at the following code:

Copy Code code as follows:

Local account = {value = 0}
function Account:new (o)--this is a colon.
o = O or {}--if the user does not supply a table, create a
Setmetatable (O, self)
Self.__index = Self
Return o
End

function Account:display ()
Self.value = self.value + 100
Print (Self.value)
End

Local A = account:new{}--Here you create an object A with the prototype account
A:display ()--(1)
A:display ()--(2)

There is a value field in the Account table with the default value of 0; When I created the instance object A, the value field was not supplied, and in the display function, because there is no value field in a, the Meta table account is found. The value of value in account is finally obtained, and the value of the Self.value on the right of the equal sign is derived from value in account. When A:display () is invoked, the following code is actually invoked:

Copy Code code as follows:

A.display (a)

In the definition of display, it becomes this way:
Copy Code code as follows:

A.value = Getmetatable (a). __index (value) + 100

The first time you call display, The Self.value on the left side of the equal sign is a.value, which is equivalent to adding a new field value in a, and when the display function is called the second time, the Value field is not found in account because a has already been in the.

Inherited

Since classes are also objects (precisely a prototype), they can also derive (inherit) methods from other classes (prototypes). This behavior is inherited and can be easily implemented in Lua. Now we have a class (prototype, in fact, in Lua, the concept of class, or very awkward, after all, with C + + head to think, or feel a little strange. ) CA:

Copy Code code as follows:

Local CA = {value = 0}

function Ca:new (o)
o = O or {}
Setmetatable (O, self)
Self.__index = Self
Return o
End

function Ca:display ()
Print (Self.value)
End

function Ca:addvalue (v)
Self.value = Self.value + V
End

Now that you need to derive a subclass of Clittlea from this CA class, you need to create an empty class that inherits all operations from the base class:

Copy Code code as follows:

Local Clittlea = Ca:new ()

Now, I've created an instance object for the CA class, and in Lua, now Clittlea is both an instance object of the CA class, a prototype, a so-called class, which is equivalent to inheriting the Clittlea class from the CA class. Again, like the following code:

Copy Code code as follows:

Local s = clittlea:new{value1 = 10}

Clittlea inherits new from the CA, however, when the clittlea:new is executed, its self parameter is represented as Clittlea, so the Wenzu of S is Clittlea,clittlea for the field __index in Clittlea. Then we'll see that s inherits from Clittlea, and Clittlea inherits from the CA. When the S:display is executed, Lua finds the display field in S, looks for Clittlea, finds the CA if the display field is still not found, and eventually finds the display field in the CA. You can think of this, if there is a display field in the Clittlea, then you will not go to the CA to find again. So, we can redefine the display field in Clittlea to implement a special version of the display function.

Multiple inheritance

Speaking of multiple inheritance, I write C + + code when the use of very little, is generally used to solve the combination, for the "combination" of this concept does not understand the friend, you can read my design pattern series of articles. Now that you've talked about multiple inheritance in Lua, it's also a summary of the way to broaden your horizons and knowledge.

When implementing a single inheritance, you rely on setting up metatable for subclasses, setting them metatable as parent classes, and setting the __index of the parent class to its own technology implementation. And multiple inheritance is the same truth, in a single inheritance, if there is no corresponding field in the subclass, you only need to look for the nonexistent field in a parent class, and in multiple inheritance, if the subclass has no corresponding field, you need to look for the nonexistent field in multiple parent classes.

As shown in the figure above, LUA searches for the display field one after the other in multiple parent classes. Instead of simply specifying __index as a parent class, we should specify __index as a function that specifies the rules for searching for fields that do not exist. This allows multiple inheritance to be implemented. There are two problems that need to be addressed:

1. Save all the parent classes;
2. Specify a search function to complete the search task.

For the multiple inheritance above, let's look at a headache code:

Copy Code code as follows:

--Find fields in multiple parent classes K
Local function search (k, pparentlist)
For i = 1, #pParentList do
Local v = pparentlist[i][k]
If V Then
Return V
End
End
End

function Createclass (...)
Local c = {}-new class
Local parents = {...}

--Class searches for a method in its meta table
Setmetatable (c, {__index = function (t, K) return search (k, parents) end})

--The Wenzu of C as its instance
C.__index = C

--Create a new constructor for this new class
function C:new (o)
o = O or {}
Setmetatable (O, self)

--Self.__index = Self is not set here, C.__index = c is already set on the above
Return o
End

--Returns a new Class (prototype)
Return C
End

--A simple class CA
Local CA = {}
function Ca:new (o)
o = O or {}
Setmetatable (o, {__index = self})
Self.__index = Self
Return o
End

function Ca:setname (strName)
Self.name = StrName
End

--A simple class CB
Local CB = {}
function Cb:new (o)
o = O or {}
Setmetatable (O, self)
Self.__index = Self
Return o
End

function Cb:getname ()
Return Self.name
End

--Create a C class whose parent class is CA and CB
Local C = Createclass (CA, CB)

--Create an instance object using the C class
Local OBJECTC = C:new{name = "Jelly"}

--Set the OBJECTC object a new name
Objectc:setname ("Jellythink")
Local newName = Objectc:getname ()
Print (NewName)

Although the code is a headache, but still continue to look. First of all, read the above code, do not understand it does not matter. Now let me explain the code above.

1. A class (prototype) was created using Createclass, and the CA and CB were set to the parent class (prototype) of this class (archetype), and the class's __index was set to a search function in the created Class (prototype). Look for fields in the search function that are not in the created class;

2. New class created, there is a constructor new, this new and previous single inheritance in the difference is not very good understanding;

3. Call the new constructor to create an instance object that has a name field;

4. Call Object:setname ("Jellythink") statement, set a new name, but in OBJECTC without this field, how to do? OK, go to the parent category, go to the CA first, find it all at once, and then call the self in this setname,setname to point to the OBJECTC; After setting, it is equivalent to modifying the name value of the OBJECTC field;

5. Call Objectc:getname (), OBJECTC still does not have this field. Look for it, CA also did not, then find, in CB found, on the call GetName, in the getname of Self point is OBJECTC. Therefore, the value of name in OBJECTC is returned in Objectc:getname, which is "Jellythink".

What else? There is nothing, for multiple inheritance, seemingly difficult to look, very troublesome, in fact, so something. If you don't understand it, come again.

What I got to protect you.

As we all know, in C + + or Java, there is access to a member function or variable in a class. Public,protected and private These several key words also know. What about in Lua? Lua is itself a "simple" scripting language, not in itself for a large project, so, its language features do not have these things, if you have to use such a protection, what to do? We still "curve the salvation of the nation". The idea is to represent an object through two table. A table is used to hold the object's private data, and another action for the object. object is implemented through a second table when it is actually manipulated. To avoid unauthorized access, the table that holds the private data of the object is not saved in the other table, but only in the closure of the existing method. Read a piece of code:

Copy Code code as follows:

function NewObject (defaultname)
Local Self = {name = DefaultName}
Local setname = function (v) self.name = v-end
Local getName = function () return Self.name end
return {SetName = setname, getName = GetName}
End

Local objecta = NewObject ("Jelly")
Objecta.setname ("Jellythink")--no colon access is used here
Print (Objecta.getname ())

This design gives the complete privacy of everything stored in the self table. When the call NewObject returns, the table cannot be accessed directly. This self table can only be accessed through functions created in the NewObject, and is equivalent to the private one saved in the Self table, which cannot be accessed directly from the outside. As you may have noticed, I didn't use a colon when I accessed the function, mainly because I could directly access the fields in the Self table, so I didn't need the extra self field, and I didn't have to have a colon.

Summarize

This article makes a few simple summaries of "object-oriented" in Lua, and it was simple to LUA, and we just used the features of LUA itself to achieve some of the bigger features, so there's nothing wrong with it and sometimes it's not good. Instead of focusing on how to understand object-oriented concepts, you should not use these object-oriented features to specifically analyze specific projects. Lua object-oriented, summary end of the end, after the actual project application, and then summed up the article, the basic article, I hope to be useful to everyone.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.