Lua 學習

Lua 學習

本節內容

  1. 迭代器與泛型for
  2. talbe
  3. metatables
  4. 協程
  5. 面向對象

1. 迭代器與泛型for

1.1 範型for爲迭代循環處理全部的內容:

首先調用迭代工廠;內部保留迭代函數,所以咱們不須要 iter 變量;而後在每個新的迭代處調用迭代器函數;當迭代器返回 nil 時循環結束。
在循環過程當中範性 for 在本身內部保存迭代函數,實際上它保存三個值:迭代函數、狀態常量、控制變量。程序員

範性 for 的執行過程:閉包

  1. in 後面表達式的值,表達式應該返回範型 for 須要的三個值:迭代函數、狀態常量、控制變量;與多值賦值同樣,若是表達式返回的結果個數不足三個會自動用 nil 補足,多出部分會被忽略。
  2. 常量和控制變量做爲參數調用迭代函數(注意:對於 for 結構來講,狀態常量沒有用處,僅僅在初始化時獲取他的值並傳遞給迭代函數)。
  3. 函數返回的值賦給變量列表。
  4. 若返回的第一個值爲 nil 循環結束,不然執行循環體。
  5. 第二步再次調用迭代函數。

具體舉例:函數

for var_1, ..., var_n in explist do block end
-- 等價於
do
    local _f, _s, _var = explist
    while true do
        local var_1, ... , var_n = _f(_s, _var)
        _var = var_1
        if _var == nil then break end
        block
    end
end

1.2 無狀態迭代器:

無狀態的迭代器是指不保留任何狀態的迭代器,所以在循環中咱們能夠利用無狀態迭代器避免建立閉包花費額外的代價。
每一次迭代,迭代函數都是用兩個變量(狀態常量和控制變量)的值做爲參數被調用,一個無狀態的迭代器只利用這兩個值能夠獲取下一個元素。學習

本身實現ipairs舉例:this

a = {"one", "two", "three"}

function iter (a, i)
    i = i + 1
    local v = a[i]
    if v then
        return i, v
    end
end

function ipairs (a)
    return iter, a, 0  -- 迭代函數、狀態常量、控制變量
end

for i, v in ipairs(a) do
    print(i, v)
end

Lua 庫中實現的 pairs 是一個用 next 實現的原始方法:lua

function pairs (t)
    return next, t, nil
end

for k, v in next, t do
    ...
end

1.3 多狀態的迭代器:

不少狀況下,迭代器須要保存多個狀態信息而不是簡單的狀態常量和控制變量,最簡單的方法是使用閉包,還有一種方法就是將全部的狀態信息封裝到 table 內,將 table做爲迭代器的狀態常量,由於這種狀況下能夠將全部的信息存放在 table 內,因此迭代函數一般不須要第二個參數。prototype

咱們應該儘量的寫無狀態的迭代器,由於這樣循環的時候由 for 來保存狀態,不須要建立對象花費的代價小;若是不能用無狀態的迭代器實現,應儘量使用閉包;儘量不要使用 table 這種方式,由於建立閉包的代價要比建立 table 小,另外 Lua 處理閉包要比處理 table 速度快些。後面咱們還將看到另外一種使用協同來建立迭代器的方式,這種方式功能更強但更復雜。代理

多狀態迭代器舉例:code

local iterator

function allwords()
    local state = {line=io.read(),pos=1 }
    return iterator,state  -- 返回迭代函數,狀態常量
end

function iterator(state)
    while state.line do
        local s,e = string.find(state.line,"%w+",state.pos)
        if s then
            state.pos=e+1
            return string.sub(state.line,s,e)
        else
            state.line=io.read()
            state.pos=1
        end
    end
    return nil
end

for i in allwords() do
    print(i)
end

--function allwords(f)
--    for l in io.lines() do
--        for w in string.gfind(l, "%w+") do
--            f(w)
--        end
--
--    end
--
--end
--allwords(print)

2. table

2.1 用table實現鏈表

舉例:orm

list=nil  -- 鏈表最末尾節點

list={next=list,value=v}  -- 鏈表建立時往前賦值

local l=list
while l do  -- 遍歷鏈表
    print(l.value)
    l=l.next
end

2.2 隊列實現

舉例:

List={}

function List.new()
    return {first=0,last=-1}
end

function List.pushleft(list,value)
    local first=list.first-1
    list.first=first
    list[first]=value
end

function List.pushright(list,value)
    local last=list.last+1
    list.last=last
    list[last]=value
end

function List.popleft(list)
    local first=list.first
    if first>list.last then error("list is empty") end
    local value = list[first]
    list[first]=nil
    list.first=first+1
    return value
end

function List.popright(list)
    local last=list.last
    if last < list.first then error("list is empty") end
    local value=list[last]
    list[last]=nil
    list.last=list.last-1
    return value
end

local a =List.new()

List.pushright(a,1)
List.pushright(a,2)
List.pushright(a,3)
List.pushright(a,4)

print(List.popright(a))  -- 4
print(List.popright(a))  -- 3
print(List.popright(a))  -- 2
print(List.popright(a))  -- 1

2.3 集合

舉例:

function Set(list)
    local set={}
    for _,l in ipairs(list) do
        set[l]=true
    end
    return set
end

reserved = Set{"while", "end", "function", "local", "local","while"}  -- 已經將table中的元素去重了
for k,v in pairs(reserved)do io.write(k," ") end  -- local function end while

2.4 table的序列化

遞歸實現table的序列化。
舉例:

function serialize(o)
    if type(o)=="number" then  -- 若是是number則直接寫入
        io.write(o)
    elseif type(o)=="string" then  -- 若是是string經過format寫入,用%q可使用雙引號表示字符串而且能夠正確的處理包含引號和換行等特殊字符的字符串
        io.write(string.format("%q",o))
    elseif type(o)=="table" then  -- 若是是table則遍歷table中的元素,遞歸調用serialize
        io.write("{\n")
        for k,v in pairs(o) do
--            io.write(" ",k," = ")
            io.write("[")
            serialize(k)
            io.write("] = ")
            serialize(v)
            io.write(",\n")
        end
        io.write("}\n")
    else
        error("can not serialize a " .. type(o))
    end
end

a={a="1",b="2",c={1,2,3,4,5},"q","w","e","r","t","y","u" }
serialize(a)
--    {
--        [1] = "q",
--        [2] = "w",
--        [3] = "e",
--        [4] = "r",
--        [5] = "t",
--        [6] = "y",
--        [7] = "u",
--        ["b"] = "2",
--        ["c"] = {
--            [1] = 1,
--            [2] = 2,
--            [3] = 3,
--            [4] = 4,
--            [5] = 5,
--        }
--        ,
--        ["a"] = "1",
--    }

3. metatables

Metatables 容許咱們改變 table 的行爲,例如,使用 Metatables 咱們能夠定義 Lua 如何計算兩個 table 的相加操做 a+b。當 Lua 試圖對兩個表進行相加時,他會檢查兩個表是否有一個表有 Metatable,而且檢查 Metatable 是否有__add 域。若是找到則調用這個__add函數(所謂的 Metamethod)去計算結果。

3.1 算數運算的metamethods

舉例:

Set={}
Set.mt={}
function Set.new(t)
    local set={}
    setmetatable(set,Set.mt)
    for _,l in ipairs(t) do set[l]=true end
    return set
end

function Set.union(a,b)
    if getmetatable(a)~=Set.mt or getmetatable(b)~=Set.mt then error("attempt to `add' a set with a non-set value",2) end
    local res=Set.new{}
    for k in pairs(a) do res[k]=true end
    for k in pairs(b) do res[k]=true end
    return res
end

function Set.intersection(a,b)  -- 取a,b的交集
    local res=Set.new{}
    for k in pairs(a) do
        res[k]=b[k]
    end
    return res
end

function Set.tostring(set)
    local s="{"
    local sep=""
    for e in pairs(set) do
        s=s..sep..e
        sep=", "
    end
    return s.."}"
end

function Set.print(s)
    print(Set.tostring(s))
end

Set.mt.__add=Set.union
Set.mt.__mul=Set.intersection


s1=Set.new {10,20,30,40,50}
s2=Set.new {30,40,50,60,70}
print(getmetatable(s1))  -- table: 0x0004b540
print(getmetatable(s2))  -- table: 0x0004b540

s3=s1+s2
Set.print(s3)  -- {60, 20, 10, 70, 50, 40, 30}
Set.print((s1+s2)*s1)  -- {50, 30, 20, 40, 10}

-- 對於每個算術運算符,metatable 都有對應的域名與其對應,除了__add、__mul 外,還有__sub(減)、__div(除)、__unm(負)、__pow(冪),
-- 咱們也能夠定義__concat 定義 鏈接行爲。__call能夠將table按照函數的方法調用,觸發__call對應的函數執行

Set.print(s1+8)
--/usr/local/bin/luajit: metatable/metamethods1.lua:64: attempt to `add' a set with a non-set value
--stack traceback:
--[C]: in function 'error'
--metatable/metamethods1.lua:19: in function '__add'
--metatable/metamethods1.lua:64: in main chunk
--[C]: at 0x0100001770

Lua 選擇 metamethod 的原則:若是第一個參數存在帶有__add 域的 metatable, Lua使用它做爲 metamethod,和第二個參數無關;不然第二個參數存在帶有__add 域的 metatable, Lua 使用它做爲 metamethod 不然報錯。

3.2 關係運算的 Metamethods

舉例:

Set={}
Set.mt={}
function Set.new(t)
    local set={}
    setmetatable(set,Set.mt)
    for _,l in ipairs(t) do set[l]=true end
    return set
end

function Set.union(a,b)
    if getmetatable(a)~=Set.mt or getmetatable(b)~=Set.mt then error("attempt to `add' a set with a non-set value",2) end
    local res=Set.new{}
    for k in pairs(a) do res[k]=true end
    for k in pairs(b) do res[k]=true end
    return res
end

function Set.intersection(a,b)  -- 取a,b的交集
    local res=Set.new{}
    for k in pairs(a) do
        res[k]=b[k]
    end
    return res
end

function Set.tostring(set)
    local s="{"
    local sep=""
    for e in pairs(set) do
        s=s..sep..e
        sep=", "
    end
    return s.."}"
end

function Set.print(s)
    print(Set.tostring(s))
end

Set.mt.__add=Set.union
Set.mt.__mul=Set.intersection
Set.mt.__tostring=Set.tostring  -- 特殊方法,print會調用metatable的tostring方法返回的字符串
Set.mt.__metatable = "not your business"  -- 特殊方法,加上這個方法後,就沒法訪問對象的metatable以及修改了


Set.mt.__le=function(a,b)
    for k in pairs(a) do
        if not b[k] then return false end
    end
    return true
end

Set.mt.__lt=function(a,b)
    return a<=b and not (b<=a)
end

Set.mt.__eq=function(a,b)
    return a<=b and b<=a
end

s1=Set.new {10,20,30,40,50,60,70}
s2=Set.new {30,40,50,60,70 }

print(s1)  -- {50, 30, 60, 70, 20, 40, 10}
print(s2)  -- {50, 70, 40, 60, 30}

print(s1<=s2)  -- false
print(s1<s2)  -- false
print(s1>=s2)  -- true
print(s1>s2)  -- true
print(s1==s1*s2)  -- false

print(getmetatable(s1))  -- not your business
print(setmetatable(s1,{}))
--/usr/local/bin/luajit: metatable/metamethods2.lua:82: cannot change a protected metatable
--stack traceback:
--    [C]: in function 'setmetatable'
--    metatable/metamethods2.lua:82: in main chunk
--    [C]: at 0x0100001770

3.3 表相關的 Metamethods

舉例:

-- 經過__index設置默認值
-- 訪問一個表的不存在的域,觸發 lua 解釋器去查找__index metamethod:若是不存在, 返回結果爲 nil;若是存在則由__index metamethod 返回結果。

window={}
window.prototype={x=0,y=0,width=100,height=100 }
window.mt={}

function window.new(o)
    setmetatable(o,window.mt)
    return o
end

--window.mt.__index=function(table,key)
--    return window.prototype[key]
--end

window.mt.__index=window.prototype  -- 這樣也能夠,就不用特地定義一個匿名函數了

w=window.new({x=10,y=20})
print(w.width)  -- 100  # 先尋找w中,沒找到width屬性,去它的metatable裏面調用__index方法,若是找到則返回,若是沒找到返回nil

print(rawget(w,width))  -- nil  # 不會經過__index的方式去獲取w中的屬性,若是沒有,直接返回nil

-- __newindex metamethod用來對錶更新,__index則用來對錶訪問。當你給表的一個 缺乏的域賦值,
-- 解釋器就會查找__newindex metamethod:若是存在則調用這個函數而不進行賦值操做。調用 rawset(t,k,v)不調用任何 metamethod 對錶 t 的 k 域賦值爲 v。
------------------------------------------------------------------------------------------------------------------------
-- 使用key爲{}隱藏默認值

local key={}
local mt={__index=function(t) return t[key] end }  -- 返回t[{}]的值,意思是若是沒有找到key,則調用__index,永遠返回t[{}]的值
function setDefault(t,d)
    t[key]=d  -- t[{}]=d
    setmetatable(t,mt)  -- 設置mt爲metatable
end
table={x=10,y=20 }
print(table.x,table.z)  -- 10   nil  # 訪問z找不到值
setDefault(table,0)
print(table.x,table.z)  -- 10   0  # 訪問z以前已經設置了默認值


------------------------------------------------------------------------------------------------------------------------
-- 監控table的實現

local index={}

local mt={
    __index=function(t,k)
        print("*access to element" .. tostring(k))
        return t[index][k]
    end,

    __newindex=function(t,k,v)
        print("update of element " .. tostring(k) .. " to " .. tostring(v))
        t[index][k]=v
    end
}

function track(t)
    local proxy={}  -- 建立代理table
    proxy[index]=t  -- 將原始table賦值到代理table的{}鍵上,外部不能訪問
    setmetatable(proxy,mt)  -- 將mt設置到proxy的metatable上,當從proxy讀取不到值的時候就必然會調用metatable的__index,就能夠實現監控
    return proxy
end

table={x=10,y=20}

table=track(table)
print(table.x)  -- *access to elementx  -- 10
table.z=30  -- update of element z to 30

------------------------------------------------------------------------------------------------------------------------
-- 只讀__index實現

function readOnly(t)
    local proxy={}
    local mt={
        __index=t,
        __newindex=function()  -- 控制修改表,保持Proxy裏面是空的,那麼修改表就必定會走__newindex方法
            error("attempt to update a read-only table",2)
        end
    }
    setmetatable(proxy,mt)
    return proxy
end

days = readOnly{"Sunday", "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday"}

print(days[2])  -- Monday
days[2]="Noday"
--/usr/local/bin/luajit: metatable/metamethods3.lua:91: attempt to update a read-only table
--stack traceback:
--[C]: in function 'error'
--metatable/metamethods3.lua:80: in function '__newindex'
--metatable/metamethods3.lua:91: in main chunk
--[C]: at 0x0100001770

4. 協程

4.1 協程實現的基礎:

Lua 的全部協同函數存放於 coroutine table 中。 create 函數用於建立新的協同程序,其只有一個參數:一個函數,即協同程序將要運行的代碼。若一切順利,返回值爲 thread類型,表示建立成功。一般狀況下, create 的參數是匿名函數。
協程有三個狀態:掛起態(suspended)、運行態(running)、中止態(dead)。建立協同程序成功時,其爲掛起態,即此時協同程序並未運行。咱們可用 status 函數檢查協同的狀態。
舉例:

-- 協程建立,狀態,執行

co= coroutine.create(function()  -- 建立協程,此時處於掛起狀態
    print("hello world")
end)

print(co)  -- thread: 0x0004afa0
print(coroutine.status(co))  -- suspended
coroutine.resume(co)  -- hello world  -- 運行協程,獲得想要的輸出。resume 運行在保護模式下,所以,若是協同程序內部存在錯誤, Lua 並不會拋出錯誤,而是將錯誤返回給 resume 函數。
print(coroutine.status(co))  -- dead  -- 協程結束,檢查狀態爲dead

4.2 yield的使用:

舉例:

-- yield掛起協程執行

co = coroutine.create(function()
    for i = 1,10 do
        print("co",i)
        coroutine.yield()
    end
end)

coroutine.resume(co)  -- co 1
print(coroutine.status(co))  -- suspended
coroutine.resume(co)  -- co 2
coroutine.resume(co)  -- co 3
coroutine.resume(co)  -- co 4
coroutine.resume(co)  -- co 5
coroutine.resume(co)  -- co 6
coroutine.resume(co)  -- co 7
coroutine.resume(co)  -- co 8
coroutine.resume(co)  -- co 9
coroutine.resume(co)  -- co 10
print(coroutine.resume(co))  -- true  # 最後一個yield後面的代碼被執行,這時候完全執行完了該協程
print(coroutine.resume(co))  -- false   cannot resume dead coroutine  # 再去執行協程,返回false,提示報錯 協程已經到了dead狀態


-- yield傳遞參數

co=coroutine.create(function(a,b,c)
    coroutine.yield(a+b,a-c)
end)

print(coroutine.resume(co,1,2,3))  -- true  3   -2  # 返回yield傳回來的結果
print(coroutine.resume(co))  -- true
print(coroutine.resume(co))  -- false   cannot resume dead coroutine

co=coroutine.create(function()
    print("co",coroutine.yield())  -- co    1   2  # 傳遞參數給yield
    a,b=coroutine.yield()
    print(a,b)  -- 1    2
end)

coroutine.resume(co)
coroutine.resume(co,1,2)
coroutine.resume(co,1,2)


-- return結果返回

co=coroutine.create(function()
    return 4,5
end)

print(coroutine.resume(co))  -- true    4   5  # return的結果被resume接收了

4.3 管道和過濾器

舉例:

-- 協同是一種非搶佔式的多線 程。管道的方式下,每個任務在獨立的進程中運行,而協同方式下,每一個任務運行在 獨立的協同代碼中。
-- 管道在讀(consumer)與寫(producer)之間提供了一個緩衝,所以 二者相關的的速度沒有什麼限制,在上下文管道中這是很是重要的,
-- 由於在進程間的切 換代價是很高的。協同模式下,任務間的切換代價較小,與函數調用至關,所以讀寫可 以很好的協同處理。
function receive(prod)  -- 執行協程,將拿到結果返回
    local status,value=coroutine.resume(prod)
    return value
end

function send(x)  -- yield 夯住,等待下次調用
    coroutine.yield(x)
end

function producer()  -- 建立一個協程,讀取輸入,並調用send,返回輸入的值,並夯住
    return coroutine.create(function()
        while true do
            local x=io.read()
            send(x)
        end
    end)
end

function filter(prod)  -- 建立一個協程,調用receive執行producer建立的協程,拿到結果後格式化,後調用send,返回格式化後的結果,並夯住
    return coroutine.create(function()
        local line = 1
        while true do
            local x= receive(prod)
            x=string.format("%5d %s",line,x)
            send(x)
            line=line+1
        end
    end)
end

function consumer(prod)  -- 循環調用receive執行filter建立的協程,並接受返回結果,打印出來
    while true do
        local x=receive(prod)
        io.write(x,"\n")
    end
end

consumer(filter(producer()))  -- 多層嵌套執行協程

4.4 用做迭代器的協同

舉例:

-- 初版,用遞歸迭代器實現輸出全部組合
function Permgen(a,n)
    if n==0 then
        printResult(a)
    else
        for i=1,n do  -- 將列表前面全部的數值和最後一個數值替換,都能出現一種狀況,而後遞歸調用,將遍歷出全部組合的狀況
            a[n],a[i]=a[i],a[n]
            Permgen(a,n-1)
            a[n],a[i]=a[i],a[n]
        end
    end
end


function printResult(a)
    for i,v in ipairs(a) do
        io.write(v," ")
    end
    io.write("\n")
end

Permgen({1,2,3},3)
--2 3 1
--3 2 1
--3 1 2
--1 3 2
--2 1 3
--1 2 3

-------------------------------------------------------------------------------------------------------------------------
-- 使用協程替換迭代器實現


function Permgen(a,n)
    if n==0 then
        coroutine.yield(a)
    else
        for i=1,n do
            a[n],a[i]=a[i],a[n]
            Permgen(a,n-1)
            a[n],a[i]=a[i],a[n]
        end
    end
end

function printResult(a)
    for i,v in ipairs(a) do
        io.write(v," ")
    end
    io.write("\n")
end

--function perm(a)  -- 在這種狀況下,被下面的方法替代了
--    local n=table.getn(a)
--    local co=coroutine.create(function()Permgen(a,n) end)
--    return function()
--        local code,res=coroutine.resume(co)
--        return res
--    end
--end

-- 通常狀況下,coroutine.wrap 比 coroutine.create 使用起來簡單直觀,前者更確切的提 供了咱們所須要的:一個能夠 resume 協同的函數,
-- 然而缺乏靈活性,沒有辦法知道 wrap 所建立的協同的狀態,也沒有辦法檢查錯誤的發生。
function perm (a)
    local n = table.getn(a)
    return coroutine.wrap(function () Permgen(a, n) end)
end

for p in perm{"a","b","c"} do

    printResult(p)

end

5. 面向對象

Lua 不存在類的概念,每一個對象定義他本身的行爲並擁有本身的形狀(shape)。然而,依據基於原型(prototype)的語言好比 Self 和 NewtonScript,在 Lua中仿效類的概念並不難。 在這些語言中, 對象沒有類。 相反, 每一個對象都有一個 prototype(原型),當調用不屬於對象的某些操做時,會最早會到 prototype 中查找這些操做。在這類語言中實現類(class)的機制,咱們建立一個對象,做爲其它對象的原型便可(原型對象爲類,其它對象爲類的 instance)。類與 prototype 的工做機制相同,都是定義了特定對象的行爲。

5.1 類的基本實現

舉例:

-- 定義方法的時候帶上一個額外的參數,來表示方法做用的對象。這個參數常常爲 self 或者 this
-- self 參數的使用是不少面嚮對象語言的要點。大多數 OO 語言將這種機制隱藏起來,這樣程序員沒必要聲明這個參數(雖然仍然能夠在方法內使用這個參數)。
-- Lua 也提供了經過使用冒號操做符來隱藏這個參數的聲明。冒號的效果至關於在函數定義和函數調用的時候,增長一個額外的隱藏參數。

Account={
    balance=0,
    withdraw=function(self,v)
        self.balance=self.balance-v
    end
}

function Account:deposit(v)
    self.balance=self.balance+v
end

Account.deposit(Account,200.00)
Account:withdraw(100.00)
print(Account.balance)

5.2 類的繼承與多重繼承

舉例:

-- 類的繼承

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

SpecialAccount=Account:new()  -- Account的子類

function SpecialAccount:withdraw(v)
    if v-self.balance>=self:getLimit() then
        error("insufficient funds")
    end
    self.balance=self.balance-v
end

function SpecialAccount:getLimit()
    return self.limit or 0
end

s=SpecialAccount:new({limit=1000.00})  -- SpecialAccount的子類

function s:getLimit()  -- 若是子類s中定義了getLimit,則不會調用SpecialAccount中的getLimit
    return self.limit*0.10 or 0
end

--s:withdraw(200)  -- insufficient funds

--print(s.balance)  -- insufficient funds

-- SpecialAccount 從 Account 繼承了 new 方法,當 new 執行的時候, self 參數指向SpecialAccount。因此, s 的 metatable 是 SpecialAccount, __index 也是 SpecialAccount。這樣, s 繼承了 SpecialAccount,後者繼承了 Account。當咱們執行:s:deposit(100.00) Lua 在 s 中找不到 deposit 域,他會到 SpecialAccount 中查找,在 SpecialAccount 中找不到,會到 Account 中查找。使得 SpecialAccount 特殊之處在於,它能夠重定義從父類中繼承來的方法(繼承和重寫父類方法)
------------------------------------------------------------------------------------------------------------------------
-- 多繼承

local function search(k,plist)
    for i=1,table.getn(plist) do
        local v=plist[i][k]
        if v then return v end
    end
end

function creatClass(...)
    local c={}
    local args={...}  -- 這裏注意,...雖然在lua中是表明不定參數,可是要獲取這些不定參數,須要使用{...}獲取,會生成一個tables,裏面放了全部的參數,以及一個key爲n,對應總共有多少個參數被接受。
    setmetatable(c,{__index=function(t,k)
--        return search(k,args)
        local v=search(k,args)   -- 這樣改造,訪問到一個函數在t中沒有的,則從父類中找到該方法後,將該方法賦值給子類t中,
                                -- 加快以後訪問該方法的速度,缺點是沒法在以後修改父類的方法,由於修改後不會影響到子類
        t[k]=v
        return v
    end})
    c.__index=c

    function c:new(o)
        o=o or {}
        setmetatable(o,c)
        return o
    end

    return c

end

Named = {}
function Named:getname()
    return self.name
end

function Named:setname(n)
    self.name = n
end

NamedAccount=creatClass(Account,Named)

account=NamedAccount:new({name="Paul"})

print(account:getname())
相關文章
相關標籤/搜索