Lua语言笔记(为热更新做铺垫)
2018-02-27 本文已影响51人
ZZ曾帅
[前言:很多基本的语法之类的在笔记中没有提及,需要在看之前了解一下lua基本语法]
-- ======lua简单知识======
print(.02 + .01)-->0.03
print(2 + "3")-->5
print("2" + "6")-->8
print("2" .. "3")-->23
print("-2e2" * "6")-->-200*6
print(157 .. 428)-->157428
-- 数字不能和字符串+
-- 匿名函数
function test_func(func)
func()
end
test_func(
function()
print("s")
end
)
-- 可变参数(求平均值)
function average(...)
local s = 0
local arg = {...} -- 这个就代表着传入的多个参数
for k, v in pairs(arg) do
s = s + v
end
print(s / #arg)
return s / #arg
end
average(1, 1, 1, 2)
-- 逻辑运算符
print(true and false)
print(true or false)
print(not true)
-- 字符串
s = string.find("Hello Lua user", "Lua", 1) --最后的参数表示从第几个开始找
print(s)
-- string.format(字符串格式化)
s = string.format("字符串格式化 %s %s", "A", "B")
print(s)-->字符串 A B
date = 2; month = 1; year = 2014
print(string.format("日期格式化 %02d/%02d/%03d", date, month, year))
-- 十进制格式化
print(string.format("%.4f", 1 / 3)) -->精确到小数点后四位
-- 案例
tab = {
string.format("%c", 83), --输出S
string.format("%+d", 17.0), --输出 + 17
string.format("%.5d", 17), --输出00017
string.format("%o", 17), --输出21
string.format("%u", 3.14), --输出3
string.format("%x", 13), --输出d
string.format("%X", 13), --输出D
string.format("%e", 1000), --输出1.000000e + 03
string.format("%E", 1000), --输出1.000000E + 03
string.format("%.3f", 13), --输出13.000
string.format("%q", "One\nTwo"), --输出"One\Two"
string.format("%s", "monkey"), --输出monkey
string.format("%20s", "monkey"), --输出 monkey
string.format("%.4s", "monkey") --输出 mon
}
for k, v in pairs(tab) do
print(k, v)
end
-- 数字转换文字
local function NumToCN(num)
local size = #tostring(num)
local CN = ""
local StrCN = {"一", "二", "三", "四", "五", "六", "七", "八", "九"}
for i = 1, size do
CN = CN .. StrCN[tonumber(string.sub(tostring(num), i, i))]
end
return CN
end
print(NumToCN(56665))
-- 模拟字符串分割
function StrSplit(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t = {}
local i = 1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
i = i + 1
end
return t
end
local a = "23245023496830,汉字。。。。"
local b = StrSplit(a, ",")
print(b[1])
-- 数组 索引是默认从1开始,但是可以自定义为从别的数字开始
array = {}
for i = -2, 2 do
array[i] = i * 2
end
for k, v in pairs(array) do
print(k, v)
end
-- ======lua难点======
-- 迭代器
-- [1].无状态的迭代器
-- 以下实例我们使用了一个简单的函数来实现迭代器,实现 数字 n 的平方:
function square(iteratorMaxCount, currentNumber) --iteratorMaxCount(状态常量),currentNumber(控制变量)
if currentNumber < iteratorMaxCount
then
currentNumber = currentNumber + 1
return currentNumber, currentNumber * currentNumber
end
end
for k, v in square, 3, 0
do
print(k, v)
end
-- ========实现简单的ipairs========
-- tip:迭代的状态包括被遍历的表(循环过程中不会改变的状态常量)和当前的索引下标(控制变量),
-- ipairs和迭代函数都很简单,我们在Lua中可以这样实现:
-- 在迭代数组的时候,如果遇到nil则会停止迭代
local tab = {1, 2, nil, 4, 5}
function iter (a, i)
i = i + 1
local v = a[i]
if v then
return i, v
end
end
function myipairs (a)
return iter, a, 0
end
for i, v in myipairs(tab) do
print(i, v)
end
print("-----对比------")
for i, v in ipairs(tab) do
print(i, v)
end
-- [2].多状态的迭代器(无法迭代有key的table)
array = {"Lua", "Tutorial", 2, [4] = 22, key1 = "ss", key2 = "nn"}
function elementIterator (collection)
local index = 0
local count = #collection
-- 闭包函数
return function ()
index = index + 1
if index <= count
then
-- 返回迭代器的当前元素
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
-- ========ipairs和pairs的异同(重要)========
-- 栗子1:
local tabFiles = {
[1] = "test2",
[6] = "test3",
[4] = "test1"
}
for k, v in ipairs(tabFiles) do --输出"test2",在key等于2处断开
print(k, v)
end
print("------------")
-- 栗子2:
local tabFiles = {
[2] = "test2",
[6] = "test3",
[4] = "test1"
}
-- 什么都没输出,为什么?因为控制变量初始值是按升序来遍历的,
-- 当key为1时,value为nil,此时便停止了遍历, 所有什么结果都没输出
for k, v in ipairs(tabFiles) do
print(k, v)
end
print("------------")
-- 栗子3:
local tabFiles = {
[2] = "test2",
[6] = "test3",
[4] = "test1"
}
for k, v in pairs(tabFiles) do --输出2 test2, 6 test3, 4 test1
print(k, v)
end
print("------------")
-- 栗子4:
-- 输出前三个 备注:因为第四个key不是整数
local tabFiles = {"alpha", "beta", [3] = "no", ["two"] = "yes"}
for i, v in ipairs(tabFiles) do
print(tabFiles [i])
end
print("------------")
for i, v in pairs(tabFiles) do --全部输出
print(tabFiles [i])
end
-- ======table的操作======
--[1] table.concat (连接)
tab1 = {1, 2, 3, 4, 5}
local concat_str_1arg = table.concat(tab1)
print(concat_str_1arg)
local concat_str_2arg = table.concat(tab1, ",")
print(concat_str_2arg)
local concat_str_3arg = table.concat(tab1, ",", 2)
print(concat_str_3arg)
local concat_str_4arg = table.concat(tab1, ",", 2, 4)
print(concat_str_4arg)
--[2] table.insert (插入)
tab1 = {"a", "b", "c", "d"}
table.insert(tab1, "e")
print(table.concat(tab1))
table.insert(tab1, 2, "1")
print(table.concat(tab1))
--[3] table.sort (排序,对数字和字母或者ASC码的都可以排序)
-- 默认从小到大排序
tab1 = {9, 5, 4, 3, 7, 11, 2, 6, 2}
table.sort(tab1)
print(table.concat(tab1, "<"))
-- 自定义从大到小排序
local function testSort(a, b)
return a > b
end
table.sort(tab1, testSort)
print(table.concat(tab1, ">"))
-- 字符串排序
tab2 = {"a", "b", "c"}
table.sort(tab2)
print(table.concat(tab2, "<"))
-- 注意以及技巧:
-- 当我们获取 table 的长度的时候无论是使用 # 还是 table.getn 其都会在索引中断的地方停止计数,而导致无法正确取得 table 的长度。
-- 可以使用以下方法来代替:
function table_leng(t)
local leng = 0
for k, v in pairs(t) do
leng = leng + 1
end
return leng;
end
tab = {1, key = 2, 3, 4}
for k, v in pairs(tab) do
print(k, v)
end
print(table.getn(tab))
print(#tab)
print(table_leng(tab))
-- ======lua元表(超级重点)======
--元表的两个函数 setmetatable getmetatable 下面是一个最简单的例子
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
--可以简化成
mytable = setmetatable({}, {})
-- 元方法
-- [1] __index元方法
-- 当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。
-- 如果__index包含一个表格,Lua会在表格中查找相应的键。
-- 案例1
mytable = setmetatable({key = 1}, {__index = function (arg, key) --第一个参数为默认参数
if(key == "key2") then
return "metatablevalue"
end
end
})
print(mytable.key, mytable.key2)
案例2
mytable = setmetatable({key1 = 1}, {__index = {key2 = 2}})
print(mytable.key1, mytable.key2)
-- [2] __newindex元方法
-- __newindex 元方法用来对表更新,__index则用来对表访问 。
-- 当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而对普通表不进行赋值操作。
-- 如果存在__newindex元方法并且普通表中已经含有该键, 则会优先对普通表进行赋值
-- 以下实例演示了 __newindex 元方法的应用:
metatable = {key2 = 1}
mytable = setmetatable({mytablekey = 22}, {__newindex = metatable})
mytable.key2 = 2
print(mytable.key2, metatable.key2)
-- [3] __add元方法(表相加)
mytable = setmetatable({1, 2, 3}, {__add = function (mytable, newtable)
for i = 1, #newtable do
table.insert(mytable, #mytable + 1, newtable[i])
end
return mytable
end
})
newtable = {4, 4, 4}
mytable = mytable + newtable
for k, v in pairs(mytable) do
print(k, v)
end
-- 或者这样写
local mt = {}
mt.__add = function(a, b)
return a.v + b.v
end
local a = {v = 10}
local b = {v = 12}
setmetatable(a, mt)
print("a + b :", a + b)
-- [4.1] __metatable元方法保护元表不被查看和修改
mytable = setmetatable({1, 2, 3}, {__metatable = "you can not get the metatable"})
print(getmetatable(mytable))
或者这样写
local mt = {}
mt.__metatable = "you can not get the metatable"
mytable = {}
setmetatable(mytable, mt)
print(getmetatable(mytable))
-- [4.2]写一个只读的表,只需跟踪所有对table的更新操作,并引发一个错误即可
function readOnly(table)
local proxy = {}
local mt = {
__index = table,
__newindex = function(table, k, v)
error("attempt to update a read-only table")
end
}
setmetatable(proxy, mt)
return proxy
end
days = readOnly({"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"})
print(days[1])
days[2] = "Noday"
-- [5] 其余的操作符元方法
-- __add对应的运算符 '+'
-- __sub对应的运算符 '-'
-- __mul对应的运算符 '*'
-- __div对应的运算符 '/'
-- __mod对应的运算符 '%'
-- __unm对应的运算符 '-'
-- __concat对应的运算符 '..'
-- __eq对应的运算符 '=='
-- __lt对应的运算符 '<'
-- __le对应的运算符 '<='
-- [6] __call元方法
-- 当调用一个不是函数的值的时候会去查找call这个元方法,例如使用table作为方法(table())来调用的时候,call元方法则会被调用,
-- func指代的是table本身的地址
local mt = {}
mt.__call = function(func, ...)
print("call table like a function", func, ...)
end
local temp = {}
setmetatable(temp, mt)
temp(1, 2, 3)
-- [7] __tostring 元方法
-- __tostring 元方法用于修改表的输出行为,类似c#重写toString
mytable = setmetatable({10, 20, 30}, {
__tostring = function(mytable)
sum = 0
for k, v in pairs(mytable) do
sum = sum + v
end
return "表所有元素的和为:" .. sum
end
})
print(mytable)
-- ======lua协同程序======
-- coroutine.create()
-- 创建coroutine,返回coroutine, 参数是一个函数,当和resume配合使用的时候就唤醒函数调用
-- coroutine.resume()
-- 重启coroutine,和create配合使用
-- coroutine.yield()
-- 挂起coroutine,将coroutine设置为挂起状态,这个和resume配合使用能有很多有用的效果
-- coroutine.status()
-- 查看coroutine的状态
-- 注:coroutine的状态有三种:dead,suspend,running,具体什么时候有这样的状态请参考下面的程序
-- coroutine.wrap()
-- 创建coroutine,返回一个函数,一旦你调用这个函数,就进入coroutine,和create功能重复
-- coroutine.running()
-- 返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个corouting的线程号
-- 使用下面的程序来了解一下这几个函数的基本用法:
co = coroutine.create(
function(i)
print(i);
end
)
coroutine.resume(co, 1) -- 1
print(coroutine.status(co)) -- dead
print("----------")
co = coroutine.wrap(
function(i)
print(i);
end
)
co(1) --1
print("----------"
co2 = coroutine.create(
function()
for i = 1, 10 do
print(i)
if i == 3 then
print(coroutine.status(co2)) --running
print(coroutine.running()) --thread:XXXXXX
end
coroutine.yield()
end
end
)
coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3
print(coroutine.status(co2)) -- suspended
print(coroutine.running()) --nil
print("----------")
-- ======lua文件IO======
####### -- [[ 在此省略,与其他语言的文件操作类似
-- ======lua垃圾回收机制======
-- 检测lua内存泄漏的案例:
collectgarbage("collect") --垃圾收集(释放内存)
local s1 = collectgarbage("count") -- 垃圾统计(占用了多少内存(kb))
print(">>>>>>>>>>>>>>>> count1", s1)
local my_list = {}
for i = 1, 1000, 1 do
local v = {}
v[1], v[2] = 1024 + i, 32 + i
my_list[v[1]] = v[2]
end
print(">>>>>>>>>>>>>>>> count2", collectgarbage("count")) -- 局部变量(v)和my_list所占用的内存
collectgarbage("collect")
print(">>>>>>>>>>>>>>>> count3", collectgarbage("count")) -- 注:使用“collectgarbage("collect")”,
局部变量v被回收,my_list没有被回收
如果这里不置为空,则出现内存泄漏了
my_list = nil
collectgarbage("collect")
print(">>>>>>>>>>>>>>>> count4", collectgarbage("count")) -- 销毁my_list之后被回收
-- 总结一: 如何监测Lua的编程产生内存泄露:
-- 1. 针对会产生泄露的函数,先调用collectgarbage("count"),取得最初的内存使用
-- 2. 函数调用后, collectgarbage("collect")进行收集, 并使用collectgarbage("count")再取得当前内存, 最后记录两次的使用差
-- 3. 从test1的收集可看到, collectgarbage("collect")被调用,并不保证一次成功, 所以, 大可以调用多次
-- 总结二: 如何避免Lua应用中出现的内存使用过大行为:
-- 1. 当然是代码实现不出现泄露
-- 2. 在测试中,其实还发现, Lua中被分配的内存,其实并不会自动回收(个人估计要么就是Lua虚拟机没有做这个事情,
-- 要么就是回收的时机是在C层), 所以, 为了避免内存过大, 应用的运行时,可能需要定期的(调用collectgarbage("collect"),
-- 又或者collectgarbage("step"))进行显式回收。
-- ======lua模拟面向对象======
-- Q:如何定义对象的方法以及调用对象的方法?
-- A:面向对象的特殊性在于它以this指针的方式传递了对象本身,并且这种操作是隐藏起来的。
-- 在Lua中使用:实现面向对象方式的调用。:只是一个语法糖,它同时在方法的声明与实现中增加一个名为self的隐藏参数(对象本身)。
Account = {balance = 1000} -- 账户余额初始为1000。
--[[ 取钱。
使用面向对象的方式隐藏了"self"参数,
"withdraw()"完整的参数列表是"Account.withdraw(self, v)"。]]
function Account:withdraw(v)
self.balance = self.balance - v
end
--[[ 使用面向对象的方式隐藏了"self"参数,
实际传递给"withdraw()"的参数是"Account"和"100.00"。]]
Account:withdraw(100.00)
print(Account.balance) --> 900.0
我们可以用.定义函数,而用:调用函数,或者反之亦然,只要我们正确的使用这个被隐藏的self参数。
Account = {balance = 1000} -- 账户余额初始为1000。
function Account.withdraw(self, v) -- 使用"."定义函数。
self.balance = self.balance - v
end
Account:withdraw(100.00) -- 使用":"调用函数。
print(Account.balance) --> 900.0
-- 存钱。
function Account:deposit(v) -- 使用":"定义函数。
self.balance = self.balance + v
end
Account.deposit(Account, 600.00) -- 使用"."调用函数。
print(Account.balance) --> 1500.0
-- Q:如何实现类?
-- A:类在面向对象语言中就好象一个模板,通过模板所创建的实例就具有模板中规定的特性。Lua中没有类的概念,
-- 每一个对象规定自己的行为,每一个对象就是自己的实例。不过在Lua中模拟“类”并不难,我们可以用继承的概念,使用两个对象,
-- 让其中一个对象作为另一个对象的“类”,
-- setmetatable(a, {__index = b}) -- b作为a的类,在a中找不到的方法都将去b中寻找。
-- 继续扩展银行账户的例子
Account = {balance = 100} -- 账户余额初始为0。
function Account:new (o)
o = o or {} -- create object if user does not provide one
setmetatable(o, self) -- 新对象的"metatable"是"Account"(或其子类)。
self.__index = self -- 新对象"metatable"中的"__index"依旧是"Account"(或其子类)。
return o
end
function Account:deposit(v)
self.balance = self.balance + v
end
function Account:withdraw(v)
self.balance = self.balance - v
end
--[[ "account1"继承了"Account"中的特性,
就好象"account1"是由"Account类"创建出来的一样。
这一句代码后,设置了"account1"的"metatable"是"Account",
"Account.__index"依旧是"Account"。]]
account1 = Account:new()
-- 这里打印的是"Account.balance","Account.balance"作为"Account"实例的默认值。
print(account1.balance) --> 100
print(Account.balance) --> 100
--[[ "account1:deposit(500.00)",实际上调用的是"account1.deposit(a, 500.00)",
"account1"中没有"deposit()",所以去找"account1"的"metatable"中的"__index",
即"getmetatable(account1).__index",即"Account"。
又因为"Account"是一个"table",所以"account1.deposit(a, 500.00)"
相当于"Account.deposit(a, 500.00)"。]]
account1:deposit(500.00)
--[[ 这里打印的是"account1.balance",
因为在"Account.deposit()"中为"self.balance"赋值的同时定义了"account1.balance"。]]
print(account1.balance) --> 600
print(Account.balance) --> 100
-- Q:如何实现继承?
-- A:上面的例子中已经初步展现了继承的方式,下面再使用一个更贴切的例子进行说明,
Account = {balance = 0}
function Account:new (o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Account:deposit (v)
self.balance = self.balance + v
end
function Account:withdraw (v)
-- 普通账户不可以透支。
if v > self.balance then error"insufficient funds" end
self.balance = self.balance - v
end
--[[ 信用卡账户继承自普通账户,可以透支。
"CreditAccount"是"Account"的一个“实例”,
但他同时也可以作为一个“类”以产生其他实例。]]
CreditAccount = Account:new{limit = 1000.00}
-- 为了让信用卡账户能够透支,需要重写"withdraw()"方法。
function CreditAccount:withdraw (v)
-- 信用卡账户在一定额度内可以透支。
if v - self.balance >= self:getLimit() then
error"insufficient funds"
end
self.balance = self.balance - v
end
function CreditAccount:getLimit ()
return self.limit or 0
end
--[[ 新的实例也可以规定自己的限额。
"CreditAccount"中没有"new()",实际调用的是"Account.new()"。]]
creditaccount1 = CreditAccount:new{limit = 2000.00}
--[[ "creditaccount1"中没有"deposit()",
"CreditAccount"中没有"deposit()",实际调用的是"Account.deposit()"。]]
creditaccount1:deposit(100.00)
-- 此时调用的是"CreditAccount:withdraw()"。
creditaccount1:withdraw(200.00)
print(creditaccount1.balance) --> -100.0
-- Q:如何实现多重继承?
-- A:将__index赋值为一个函数,函数中可以搜索想要找的表(“父类”)。
-- 还记得吗,当__index是个函数时,Lua调用它,以”table”和缺失的”key”作为参数。而当__index是一个”table”时,
-- Lua直接以缺失的”key”作为它的”key”再次访问他(相当于拿着缺失的”key”在它这张”table”中寻找)。
-- ------------------- "Account类" -------------------
Account = {balance = 0}
function Account:new (o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Account:deposit (v)
self.balance = self.balance + v
end
function Account:withdraw (v)
if v > self.balance then error"insufficient funds" end
self.balance = self.balance - v
end
--------------------------------------------------
-- look up for 'k' in list of tables 'plist'
local function search(k, plist)
for i = 1, #plist do
local v = plist[i][k] -- try 'i'-th superclass
if v then return v end
end
end
function createClass(...)
local c = {} -- new class
for i = 1, select('#', ...) do
-- arg = {[1] = Account, [2] = Named}。
arg[i] = select(i, ...)
end
--[[ class will search for each method in the list of its
parents ('arg' is the list of parents)]]
setmetatable(c, {__index = function (t, k)
return search(k, arg)
end})
-- prepare 'c' to be the metatable of its instances
c.__index = c
-- define a new constructor for this new class
function c:new (o)
o = o or {}
setmetatable(o, c)
return o
end
-- return new class
return c
end
Named = {} -- 姓名类,记录账户的姓名。
function Named:getname ()
return self.name
end
function Named:setname (n)
self.name = n
end
-- 创建一个新类"NamedAccount",其继承于"Account"与"Named"。
NamedAccount = createClass(Account, Named)
account = NamedAccount:new{name = "Paul"}
--[[ "account"中没有"getname",
所以找"account"的"metatable.__index",
"metatable"是"NamedAccount",
"NamedAccount"的"__index"还是"NamedAccount"。
而"NamedAccount"中依旧没有"getname()",
所以找"NamedAccount"的"metatable.__index",是个函数,
所以Lua调用这个函数,并将"NamedAccount"和"getname"作为参数传入。
函数中又调用"search()","search()"中首先在"Account"中找"getname",
没找到,又在"Named"中找"getname",找到了,所以调用"getname()"。]]
print(account:getname()) --> Paul
多重继承的效率可能比单一继承的效率低很多(因为多了search()这个过程)。如果想提高效率的话可以将找到的父类的函数拷贝到子类中,
setmetatable(c, {__index = function (t, k)
local v = search(k, arg)
t[k] = v -- "Named.getname()"存储在了"account"中。
return v
end})
-- 这样,除了第一次调用,之后的调用实际上是调用子类中拷贝过来的父类的函数,省去了search()的过程,
-- 效率就高很多。但是这种做法也有缺陷,在程序运行起来之后,就很难改变父类中的方法了,因为即使更改了,
-- 子类也不会继承过去(子类保存了父类原先的方法)。
-- Q:如何定义私有成员或私有方法?
-- A:使用两个”table”,其一存储私有成员,另一个存储公有成员和公有方法,两个”table”组成”Closure”,
-- 私有”table”作为公有”table”的”Closure”被访问,私有方法直接存储在”Closure”中,
function newAccount (initialBalance)
-- 私有"table"。
local self = {
balance = initialBalance, -- 余额。
count = 0 -- 积分。
}
-- 私有方法,未导出到公有"table"中,外部无法访问。
local addCount = function (v)
self.count = self.count + v * 0.1 -- 消费的10%作为积分。
end
local withdraw = function (v)
self.balance = self.balance - v
addCount(v)
end
local deposit = function (v)
self.balance = self.balance + v
end
local getBalance = function () return self.balance end
local getCount = function () return self.count end
-- 公有"table"。
return {
withdraw = withdraw,
deposit = deposit,
getBalance = getBalance,
getCount = getCount
}
end
account = newAccount(100)
print(account.balance) --> nil
print(account.count) --> nil
print(account.getBalance(), account.getCount()) --> 100 0
account.deposit(500)
print(account.getBalance(), account.getCount()) --> 600 0
account.withdraw(100)
print(account.getBalance(), account.getCount()) --> 500 10
-- 附加:
-- 1、Lua中的”table”与面向对象编程中的对象有很多相似的地方。像对象一样,”table”有成员变量;
-- 像对象一样,”table”本身与其存储的值相互独立,特别在于两个不同的对象拥有相同的值,但他们依旧是不同的对象。
-- 反之,一个对象在不同的时间可以有不同的值,但对象本身不会改变;像对象一样,”table”的生命周期与其被谁创建以及在哪儿被创建无关。
-- 2、Lua中的面向对象编程有意思的地方在于,当你需要增加新的方法时,既可以在“类”中添加,也可以在“实例”中直接添加。
-- -- 以添加一个“增加积分”的方法为例。
-- -- 在“类”中添加,适用于许多用户均需要该方法。
-- function CreditAccount:addCount(count) ... end
-- -- 在“实例”中直接添加,适用于少数用户需要该方法。
-- creditaccount1 = CreditAccount:new()
-- creditaccount1.addCount = function(self, count) ... end
-- 3、Lua使用”table”表示对象,本身不提供私有性机制。Lua的设计初衷是针对于中小型程序,
-- 通常他们是一个大型系统的一部分。因此Lua避免设计上的冗余以及过多的人为限制,如果对象中的某些成员你不该访问,
-- 那么你最好就”just do not do it”。Lua提供给程序员“meta-mechanisms”,程序员可以通过他们模拟许多需要的特性。