--[[
Table:
元方法: 当表达式中混合了不同元表的值时, 先看第一个值有无对应元表, 没有再看第二个对象的.
两个对象都没有,应发一个错误.
算术类的:__add加法, __mul乘法, __sub减法, __div, __unm(相反数), __mod取模, __pow乘幂, __concat连接操作符
关系类的:__eq等于, __lt小于, __le大于, 其他的进行转换:a~=b=>not(a==b), a>b=>b=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