ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
# 17 Lua 面向对象 Lua中的table就是一种对象,看以下一段简单的代码: ```lua 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) ``` 上述代码会输出tb1 ~= tb2。说明两个具有相同值得对象是两个不同的对象,同时在Lua中table是引用类型的。我们是基于table来实现的模块,在table中可以定义函数,也就是说,每个table对象都可以拥有其自己的操作。看一段代码: ```lua Account = {balance = 0} function Account.withDraw(v) Account.balance = Account.balance - v end Account.withDraw(10) --调用函数 print(Account.balance) ``` 上面的代码创建了一个新函数,并将该函数存入Account对象的withDraw字段中,然后我们就可以调用该函数了。不过,在函数中使用全局名称Account是一个不好的编程习惯,因为这个函数只能针对特定对象工作,并且,这个特定对象还必须存储在特定的全局变量中。如果改变了对象的名称,withDraw就再也不能工作了。例如以下代码: ```lua Account = {balance = 0} function Account.withDraw(v) Account.balance = Account.balance - v end Account.withDraw(10) --调用函数 print(Account.balance) a = Account Account = nil a.withDraw(100) ``` ```lua -10 lua: test14_class.lua:23: attempt to index a nil value (global 'Account') stack traceback: test14_class.lua:23: in field 'withDraw' test14_class.lua:32: in main chunk [C]: in ? ``` 这样就会出现错误。我在这里使用Account创建了一个新的对象a,当将Account赋值为nil时,应该要对a对象不产生任何影响。但是,由于在函数withDraw内部使用了Account,而不是变量a,所以就出现了错误。如果我们将withDraw函数内部的Account.balance = Account.balance – v语句修改为:a.balance = a.balance – v,这样就不会出现错误了。这就表明,当我们需要对一个函数进行操作时,需要指定实际的操作对象,即这里的a,这就需要一个额外的参数来表示该操作者,就好比C++中的this一样,只不过这里将这个关键字换成了self,换完以后的代码如下: ```lua 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) ``` 这样再调用,就不会出现错误了。 使用self参数是所有面向对象语言的一个核心。大多数面向对象语言都对程序员隐藏了self参数,从而使得程序员不必显示地声明这个参数。Lua也可以,当我们在定义函数时,使用了冒号,则能隐藏该参数,那么上述代码使用冒号来改下,就是下面这个样子了。 ```lua Account = {balance = 0} function Account:withDraw(v) --注意这里写的是":" self.balance = self.balance-v end a = Account Account = nil a:withDraw(100) --注意这里调用时,也需要使用":" print(a.balance) ``` 冒号的作用很简单,就是在方法定义中添加一个额外的隐藏参数,以及在一个方法调用中添加一个额外的实参。冒号只是一种语法便利,并没有引入任何新的东西;如果你愿意,你可以可以不使用self,而是在每次定义一个函数时,手动的加上self,只要你处理好了self,它们都是一样的。 这里乱乱的讲了一些Lua中的东西,主要还是说了table是一个不一样的东西,还有self。接下来,就正式进入面向对象的世界。不要忘了,上面总结的东西是非常有用的。