--[[
Table:
元方法: 当表达式中混合了不同元表的值时, 先看第一个值有无对应元表, 没有再看第二个对象的.
两个对象都没有,应发一个错误.
算术类的:__add加法, __mul乘法, __sub减法, __div, __unm(相反数), __mod取模, __pow乘幂, __concat连接操作符
关系类的:__eq等于, __lt小于, __le大于, 其他的进行转换:a~=b=>not(a==b), a>b=>b<a, a>=b=>b<=a
库定义的:__tostring, __metatable, 设置__metatable="xxx", getmetatable返回"xxx", setmetatable
引发错误, 起到不能设置元表的保护作用.
关于访问的:
__index: 访问table中不存在的字段时, 没有这个元方法时返回nil, 有的话, 由它返回结果.
__newindex: 当对table中不存在的索引赋值时, 查找它, 调用它而不是赋值, 如是一个table,在此table
中赋值,而不是原来的table.
插入/删除: 一般下标从1开始
table.insert(t,index,v) 指定位置插入元素, 后续元素往后移动
table.insert(t,v) 没有位置参数,添加到数组末尾, 这可以实现 栈--压入
table.remove(t) 栈--弹出
table.insert(t,1,v) 起始处插入, 实现 队列--入队
table.remove(t,1) 从另一端删除(并返回元素), 队列--出队 效率不高,需移动元素
排序: table.sort()
连接: table.concat()
]]--
--[[
函数:
闭包,闭合函数, Lua可以说没有'函数', 都是closure, 函数是特殊的closure.
closure: 一个函数及访问的非局部变量(upvalue). 没有upvalue就是传统函数
function newCounter() local i = 0 --非局部变量upvalue return function() --匿名函数 i = i + 1 return i end end c1 = newCounter() --返回一个闭包:匿名函数和它访问的upvalue print(c1()) --执行 print(c1()) --同一个闭包 c2 = newCounter() --返回另一个闭包环境
沙盒:
do local oldOpen = io.open() local accessOK = function(filename, mode) --检查权限 end io.open = function(filename, mode) --重新定义 if accessOK(filename, mode) then --确保使用安全. 形成沙盒环境 return oldOpen(filename, mode) --调用原系统库函数 else return nil, "access denied" end end end
尾调用消除:
尾调用: function f(x) return g(x) end --调用完g(x)无事可做.
消除: 不需要返回f(),不保存它的栈信息, 直接返回调用f的点. 相当于g(x)就是goto的功能.
]]--
--类:
Account = {balance = 0} --balance是公有成员变量 --new可视为构造函数 function Account:new(o) o = o or {} --将新对象实例的meatatable指向Account setmetatable(o,self) self.__index = self --Account的__index指向自己 return o end --deposite被视为Account类的公有成员函数 function Account:deposit(v) --这里的self表示对象实例本身 self.balance = self.balance + v --这里得这么理解:local accout = Accout(Accout, {}); accout.deposite(accout,v) end --下面的代码创建两个Account的对象实例 --通过Account的new方法构造基于该类的示例对象。 a = Account:new() --[[ 这里需要具体解释一下,此时由于table a中并没有deposite字段,因此需要重定向到Account, 同时调用Account的deposite方法。在Account.deposite方法中,由于self(a对象)并没有balance 字段,因此在执行self.balance + v时,也需要重定向访问Account中的balance字段,其缺省值为0。 在得到计算结果后,再将该结果直接赋值给a.balance。此后a对象就拥有了自己的balance字段和值。 下次再调用该方法,balance字段的值将完全来自于a对象,而无需在重定向到Account了。 --]] a:deposit(100.00) print(a.balance) --输出100 b = Account:new() b:deposit(200.00) print(b.balance) --输出200 --下面将派生出一个Account的子类,以使客户可以实现透支的功能。 SpecialAccount = Account:new() --此时SpecialAccount仍然为Account的一个对象实例 --SpecialAccount将为Account的子类,下面的方法withdraw可以视为SpecialAccount --重写的Account中的withdraw方法,以实现自定义的功能。 function SpecialAccount:withdraw(v) --此时的self将为对象实例。 if v - self.balance >= self:getLimit() then error("Insufficient funds") end self.balance = self.balance - v end
--在执行下面的new方法时,table s的元表已经是SpecialAccount了,而不再是Account。
s = SpecialAccount:new{limit = 1000.00}
--在调用下面的deposit方法时,由于table s和SpecialAccount均未提供该方法,因此访问的仍然是
--Account的deposit方法。
s:deposit(100)
--此时的withdraw方法将不再是Account中的withdraw方法,而是SpecialAccount中的该方法。
--这是因为Lua先在SpecialAccount(即s的元表)中找到了该方法。
s:withdraw(200.00)
print(s.balance) --输出-100