• 友链

  • 首页

  • 文章归档
h u a n b l o g
h u a n b l o g

欢

HI,Friend

04月
21
Lua

Lua面向对象编程

发表于 2022-04-21 • 字数统计 4652 • 被 1,697 人看爆

前言

Lua语言中的一张表就是一个对象。首先,表与对象一样,可以拥有状态。其次,表与对象一样,拥有一个与其值无关的的标识(self);特别地,两个具有相同值的对象(表)是两个不同的对象,而一个对象可以具有多个不同的值;最后,表与对象一样,具有与创建者和被创建位置无关的生命周期。
Account = {balance = 20}
function Account.withdraw(v)
    Account.balance = Account.balance - v
end

Account.withdraw(10)
print(Account.balance)      --> 10

Account使用全局名称,只能针对特定方法

修改后就不能访问了

a, Account = Account, nil

a.withdraw(10)
print(Account.balance)      --> ERROR!

a和Account公用同一段地址,这时Account赋值为nil,当调用a.withdraw(10)时,其实是调用Account.withdraw,而Account已经为nil了,所以出错
解决办法:可以看到a还保留着Account,可以将a当成参数传进去,这样就可以a.withdraw()等于Account.withdraw

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

a, Account = Account, nil

a.withdraw(a, 10)
print(a.balance)      --> 10

self参数大多数编程语言都是隐藏的,Lua可以使用:隐藏该参数

Account = {balance = 20}
function Account:withdraw(v)
    self.balance = self.balance - v
end

a, Account = Account, nil
a:withdraw(10)
print(a.balance)            --> 10

--不使用:调用也需要传入参数
function Account:deposit(v)
    self.balance = self.balance + v
end

Account.deposit(Account, 30)
Account.deposit(30)             --> 报错
print(Account.balance)          --> 40

类

采用原型的方式
当对象(类的实例)遇到一个未知操作时会首先在原型中查找。

例:如果有两个对象A和B,要让B成为A的一个原型

setmetatable(A, {__index = B})

在此之后,A就会在B中查找所有它没有的操作。

例如:使用__index元方法从Account继承这些操作(假设Account是具有多种方法的函数)

Account = {balance = 20}

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

local mt = {__index = Account}

function Account.new(o) 
    o = o or {}             -- 如果Account没有则创建一个新表
    setmetatable(o, mt)     -- 将mt转成o类型,即o继承mt的所有发那个发
    return o
end

a = Account.new{balance = 20}
a:deposit(100)
print(a.balance)            --> 120

当a时,a会将mt作为其元表。当调用a:deposit(100.00)时,实际上调用的是a.deposit(a,100.00)。不过,Lua语言无法在表a中找到字段"deposit",所以它会在元表的__index中搜索。此时的情况大致如下:

getmetatable(a).__index.deposit(a, 100.00)

a的元表是mt,而mt.__index是Account。因此,上述表达式等价于:

Account.deposit(a,100.00)

即,Lua语言调用了原来的deposit函数,传入了a作为self参数。因此,a从Account继承了函数deposit。同样,它还从Account继承了所有的字段。

改动

function Account.new(o) 
    o = o or {}   
    self.__index = self          -- 如果Account没有则创建一个新表
    setmetatable(o, self)     -- 将mt转成o类型,即o继承mt的所有发那个发
    return o
end

b = Account.new()
print(b.balance)                --> 20  

b中Account.new没传参,则创建新的表,继承自Account

继承

基类

Account = {balance = 0}
function Account:new(o)
    o = o or {}
    self.__index = self
    setmetatable(o, 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()      --实现继承基类
s = SpecialAccount:new{limit = 100}
s:deposit(50)
print(s.balance)                    --> 50

SpecialAccount就像继承其他方法一样从Account继承了new。不过,现在执行new时,它的self参数指向的是SpecialAccount。因此, s的元表会是SpecialAccount,其中字段__index的值也是SpecialAccount。因此,s继承自SpecialAccount,而SpecialAccount又继承自Account。之后,当执行s:deposit(100.00)时,Lua语言在s中找不到deposit字段,就会查找SpecialAccount,仍找不到deposit字段,就查找Account并最终会在Account中找到deposit的最初实现。

可以对基类方法重定义

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

这样调用withdraw时,会现在SpecialAccount中查找

私有性

function newAccount(initialBalance)
    local self = {balance = initialBalance}
    local withdraw = function(v)
                self.balance = self.balance - v
                end

    local deposit = function(v)
                self.balance = self.balance + v
                end

    local getBalance = function() 
                return self.balance 
                end
    return {
        withdraw = withdraw,
        deposit = deposit,
        getBalance = getBalance
    }
    
end



acc = newAccount(100, 100)
acc.withdraw(40)
print(acc.getBalance())         --> 60

只能通过newAccount来访问

function newAccount(initialBalance)
    local self = {
        balance = initialBalance,
        LIM = 10000.00
    }
    local extra = function()
        if self.balance > self.LIM then
            return self.balance*0.10
        else
            return 0
        end
    end

    local getBalance = function()
        return self.balance + extra()
    end
end
分享到:
Lua垃圾收集
Lua元表和元方法
  • 文章目录
  • 站点概览
欢

网红 欢

你能抓到我么?

Email RSS
看爆 Top5
  • mac系统版本与Xcode版本有冲突 4,080次看爆
  • JAVA_HOME环境配置问题 3,731次看爆
  • AssetBundle使用 3,499次看爆
  • VSCode配置C++开发环境 3,257次看爆
  • Lua反射 3,133次看爆

Copyright © 2025 欢 粤ICP备2020105803号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图