Lua语言笔记(为热更新做铺垫)

[前言:很多基本的语法之类的在笔记中没有提及,需要在看之前了解一下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”,程序员可以通过他们模拟许多需要的特性。
-- ======结束======
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,729评论 0 38
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,444评论 25 707
  • 让我们荡起双桨 2016-05-24 冰棍儿姑娘 不乖小王子日志 一直都很喜欢《让我们荡起双桨》那支歌,但是竟然发...
    蔚宇宙阅读 553评论 0 0
  • 又一三月浓愁共轻风盈袖, 未觉经身处腐草生芳华瘦, 放眼门庭旧 门外青山长相守, 细水上 一扁舟, 应是难得风月人...
    君山南我亭西阅读 2,967评论 0 0
  • 添加相机插件ionic plugin add cordova-plugin-camera添加文件上传插件ionic...
    lhl_012阅读 413评论 0 0