Lua中self 、自索引及其面向对象应用代码示例

一、Lua表的self标识

在lua中,表拥有一个标识:self。self类似于c++中的this指针和python中的self。在lua中,提供了冒号操作符来隐藏这个参数,例如:

t1 = {
    id = 1, 
    name = "panda",
    addr = "beijing"
}

-- 使用冒号语法实现
function t1:getId()
    return self.id
end

function t1:setId(val)
    self.id = val
end

t1:setId(10)
print(t1:getId())

-- 使用点语法实现
function t1.getName(obj)  -- 需要将表作为参数传入
    return obj.name
end

function t1.setName(obj, val)
    obj.name = val
end

t1.setName(t1, "mark")
print(t1.getName(t1))

运行结果:

在这里插入图片描述
冒号只是一种语法机制,提供的是便利性,并没有引入任何新的东西。使用冒号完成的事情,都可以使用点语法来完成。
两者有什么区别呢?

  1. lua 为冒号提供了独有的指令:self
  2. 从用法上来说,使用点语法实现需要传入表对象,而冒号就显得较为简洁了。

二、自索引

t2 = {id = 2, name = "lwang", age = 18}


meta_t2 = {
    -- __index = meta_t2,  -- 为什么写在这里不行,因为此时 meta_t2 还不存在,所以是nil
    addr = "shenzhen"
}

meta_t2.__index = meta_t2;  -- 自索引,自己索引自己

setmetatable(t2, meta_t2)

print(t2.addr)

运行结果:
在这里插入图片描述

三、自索引实现继承

father = {a = 1, b = 2}
function father:fatherSayHello()
    print("father say hello: ", father.a, father.b)
end

father.fatherSayHello()

father.__index = father

son = {a = 10, b = 20}
function son:sonSayHello()
    print("son say hello")
end

son.sonSayHello()

setmetatable(son, father)  -- 设置元表

son.sonSayHello()

son.fatherSayHello()  --子类son有元表,并且有__index = father,指向父类的表,调用父类的方法

运行结果:
在这里插入图片描述

四、Lua 模拟类的实例化(带参构造)

-- 4.  面向对象 类的实例化(带参构造)

stuInfo = {
    id = 1, 
    name = "panda",
    age = 18
}

-- stuInfo stu1 stu2 都是同一张表
stu1 = stuInfo
stu2 = stu1
print(stuInfo, stu1, stu2)

print(stuInfo.id, stu1.id, stu2.id)
stuInfo.id = 100
print(stuInfo.id, stu1.id, stu2.id) -- 都会休改为:100

print("")

stuInfo.__index = stuInfo  -- 设置自索引

function stuInfo:newInstance(tab)
    obj = tab or {}
    setmetatable(obj, self) -- 为obj设置元表为self 也就是stuInfo  谁调用newInstance,self就是谁
    -- self.__index = self
    return obj
end

-- stu3 接收newInstance出来的实例
stu3 = stuInfo:newInstance({id = 3, age = 20})
print("stu3: ", stu3.id, stu3.name, stu3.age)  -- name会使用stu3 元表也就是stuInfo中的name的值
print("")


stu4 = stu3:newInstance()
print("stu4: ", stu4.id, stu4.name, stu4.age)  -- 输出 nil nil nil 
print("")

stu3.__index = stu3   -- 设置自索引
stu5 = stu3:newInstance({id = 1111})
print("stu5: ", stu5.id, stu5.name, stu5.age)  -- 输出 nil nil nil 
print("")

运行结果:
在这里插入图片描述

结果分析:
为什么stu3可以正常输出,stu4为什么输出都是nil?

因为:stu3 = stuInfo:newInstance({id = 3, age = 20}) ,stu3 在实例化的过程中,传了参数:id 和 age 所以,id 和 age 直接输出3 和 20 没有问题,在stu3输出name的时候,因为stu3 没有name索引,会找自己的元表,也就是stuInfo,触发 stuInfo的__index因为stuInfo.__index 指向的是自己 (设置了自索引 stuInfo.__index = stuInfo),所以会到stuInfo表中找name 找到 name = “panda” 输出:panda

而,stu4是通过stu3实例化出来的(stu4 = stu3.newInstance())且没有传递参数,在输出stu4的id name 和 age 时,本身都没有,就会找stu4的元表,stu4的元表是stu3。 关键就在于 stu3 没有__index元方法,所以stu4输出的都是nil

如何让stu4 正常输出呢?两种解決方法:

    -- 1. 为stu3 设置自索引
    stu3.__index = stu3  

    -- 2. 直接在newInstance 方法中 通过 self.__index = self 为调用者设置自索引
    function stuInfo:newInstance(tab)
        obj = tab or {}
        setmetatable(obj, self) -- 为obj设置元表为self 也就是stuInfo  谁调用newInstance,self就是谁
        self.__index = self  -- 为调用者设置自索引
        return obj
    end

五、多重继承

grandfather = {id = 1, name = "grandfather"}
grandfather.__index = grandfather


father = {name = "father"}
father.__index = father

-- 设置father的元表为grandfather
setmetatable(father, grandfather)

son = {name = "son"}
-- 设置son的元表为father
setmetatable(son, father)

print(grandfather.id, father.id, son.id) -- 输出: 1 1 1
print(grandfather.name, father.name, son.name) -- 输出: grandfather     father  son

运行结果:
在这里插入图片描述
结果分析:
先分析id:

  • grandfather.id 因为grandfather有id 所以直接输出1
  • father.id 因为father没有id索引,会找fahter的元表,也就是grandfather,触发grandfather的__index 此时__index指向grandfather本身,grandfather本身就是一张表,就会找自己有没有id索引,找到id = 1返回
  • son.id 因为son没有id索引,会找son的元表,也就是father,触发father的__index 此时__index指向father本身, father本身就是一张表,就会找自己有没有id索引,找到id = 1返回, 没有继续找会找fahter的元表,也就是grandfather,触发grandfather的__index 此时__index指向grandfather本身,grandfather本身就是一张表,就会找自己有没有id索引,找到id = 1返回

分析name:
name 索引因为都有,所以正常输出

六、子类重写父类方法

stuInfo = {
    id = 1, 
    name = "panda",
    age = 18,
    say = function()
        print("stuInfo say.")
    end
}

function stuInfo:newInstance(tab)
    obj = tab or {}
    setmetatable(obj, self) -- 为obj设置元表为self 也就是stuInfo  谁调用newInstance,self就是谁
    self.__index = self  -- 设置自索引
    return obj
end

function stuInfo:getId()
    return self.id
end

function stuInfo:setId(newId)
    self.id = newId
end

stu1 = stuInfo:newInstance()

stu2 = stu1:newInstance()


print(stuInfo, stu1, stu2)
print(stuInfo.id, stu1.id, stu2.id)  -- 如果子类没有赋值,默认会使用父类的值;如果父类的成员或方法发生变化会影响子类,前提是子类没有重写

stuInfo.age = 25
print(stuInfo.age, stu1.age, stu2.age)

stu1.id = 100   -- stu1以下都会改变  这就是重写
print(stuInfo.id, stu1.id, stu2.id)


print("")

stuInfo.say()
stu1.say()
stu2.say()

print("")

function stu1:say()    -- stu1 重写say方法
    print("stu1 say.")
end
stuInfo.say()
stu1.say()    -- stu1 调用自己的say方法
stu2.say()    -- stu2 调用stu1的say方法

运行结果
在这里插入图片描述

七、成员私有化

function personInfo()

    -- 将成员属性隐藏起来
    local members = {
        id = 1,
        name = "lwang",
        age = 25
    }

    local function getId()
        return members.id
    end

    local function getName()
        return members.name
    end

    local function setId(id)
        members.id = id
    end

    local function setName(name)
        members.name = name
    end

    -- 对外暴露的方法
    return {
        getId = getId,
        setId = setId,
        getName = getName,
        setName = setName
    }
end


p1 = personInfo()

print(p1.getId(), p1.getName())


p1.setId(22)
p1.setName("mark")
print(p1.getId(), p1.getName())

运行结果
在这里插入图片描述

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值