学Lua你必须要清楚的要点之 元表与面向对象

Lua Tbale

对lua中的不太了解的话请写阅读这篇文章加深对的认识
学Lua你必须要清楚的要点之 Table

元表

作者认为lua中最为重要的就是table这个类型,可以说几乎lua的所有都依附于table。table的相关介绍这里不多赘述(资料很多很容易了解到)。这里主要介绍一下元表的概念。

lua中每个值都有一套预定义的操作集合(例如+ - …)即它的行为规则,即使table非常强大,但如果仅仅只遵循预先制定的规则的话往往会很局限。比如我们没法相加两个table,这是因为在table的预定义操作集合中没有定义**“+”**这个操作。我们可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作

例:在lua中,每个值有一个元表,tableuserdata可以有自己独立的元表。lua在创建table时是不会创建元表的。我们可以通过setmetatable(tab, mtab) 来给一个table设置或修改元表。

在lua中只能设置table的元表元方法 ——> 如何实现两个table相加 首先会检查两者之一是否有元表(这里不一定两者必须都有,也不需要两者的元表一定要一样)table ab 如果一方有元表且定义了元方法,则会使用这个元方法,如果a b 都存在原方法,会取前者的元方法

元方法

1、算术类的元方法:add(加)、sub(减)、mul(乘)、div(除)、unm(相反数)、mod(取模)、pow(乘幂)、concat(连接操作符)

2、关系类的元方法:eq(等于)、lt(小于)、le(小于等于) __

3、库定义的元方法:tostring(print时调用)、metatable(设置后不可修改元表)

4、table访问的元方法:index(查询table)、newindex(修改table的字段)、__mode(弱引用table)

而这第四点中所提到的元方法将会使我们去构造lua中的面向对象

(提示:所述的元方法都是带双下划线开头的例如__add)

-- 改写tostring
local Mytable = {}
function Mytable.tostring (tab)
    local str = "{"
    for k,v in pairs(tab) do
        str = str..k.."="..tostring(v)..","
    end
    str = str.."}"
    return str
end
mtab = {}
tab = {15,a =  10 , b = "hi",100}
print(tab)
mtab.__tostring = Mytable.tostring -- 设置了该mtab的元方法
setmetatable(tab,mtab) -- 将mtab设置为tab的元表
print(tab)

面向对象

讲面向对象那首先要讲的就是类。类,是面向对象语言极为重要的概念,它是进行面向对象编程的基础。类是定义同一类所有对象的变量和方法的蓝图或原型。当创建类的实例时,就建立了这种类型的一个对象,然后系统为类定义的实例变量分配内存。然后可以调用对象的实例方法实现一些功能。在lua中如何判断一个集合是否是类呢,主要看它的实例之间是否独立,彼此之间操作不会影响各自集合中的属性。

如何在lua中定义一个类

其实只需要两个步骤:

1**.设置(__index)**

2.创建实例是设置元表元方法:当我们访问table中不存在的字段时,它首先会检查__index 这个元方法,如果有这个元方法,就由元方法来提供结果,如果没有则为nil。

实现继承

我们已经知道了**(__index)**用于当前table如果查询不到某一字段时会去这个元方法中找寻结果。lua中模拟继承也是通过此来完成的。步骤:

设置一个tableA的__index元方法 => 基类

将tableA设置为tableB的元表 => 继承

-- 实现类与类继承
function class(classname,super)
	local superType = type(super)
	local cls
	if super then
		cls = {}
		setmetatable(cls, {__index = super})
		cls.super = super
	else
		cls = {ctor = function() end}
	end
	cls.__cname = classname
	cls.__index = cls
	function cls.new(...)
		local instance = setmetatable({}, cls)
		instance.super = cls.super
		instance:ctor(...)
		return instance
	end
	return cls	
end
-- 使用
SuperClassA = {...}
ClassA = class("ClassA",SuperClassA) -- 设置ClassA的元表为SuperClassA,且添加了new方法创建实例
local classAInstance = ClassA.new();
多态

简单介绍就是父类引用指向子类对象,并调用该子类重载的父类方法。调用方法时会根据实际的对象类型进行动态绑定。但lua中没有类型这个概念,所以只能遵循基类生成的对象只能使用基类的方法,子类如果重写了基类的方法,子类对象只能使用子类重写的方法。

多重继承

多重继承意味着一个类可以具有多个基类。这里依然需要通过**(__index)**来实现多重继承。

我们之前只是用table来作为**(__index),如果要实现多重继承的话,关键在于用一个函数作为(__index)。若一个table的元表的(__index)字段是一个函数,当在table中找不到一个key时,就会调用这个函数,基于这点可以让(__index)**函数在其他地方查找缺失的key

local Class = {}
function Class:search(k,plist)
  -- 从父类列表中搜索k值
    for i = 1,#plist do
        local v = plist[i][k]
        if v then
          return v
        end
    end
end
function Class:CreateClass(p1,p2)
  -- 这里简单的只多重继承两个类
    local c = {}
    local parents = {p1,p2}
    setmetatable(c,{__index = function(t,k) return self:search(k,parents)  end})
    c.__index = c
    function c:new(o)
        o = o or {}
        setmetatable(o,c)
        return o
    end
    return c
end
封装

lua的作者其实自己有表明过并不是打算让lua去构建需要很多程序员长期投入的大型程序,lua其实定位在于开发中小型程序,这些通常是一个更大的系统的一部分。参与编程的程序员一般只有一名或是几名,甚至还可以是非程序员(这可能是索引启始为1的缘由)。Lua在基础设计中并没有提供私密性机制,但可以通过其他方法来实现。它的作者提供了一种方法。这种方法基本思想是通过两个table来表示一个对象,一个table来保存对象状态,一个table用来和外界交流。

--一个例子
newCustomer = function(money)
    -- self table 来保存对象的状态
    local self = {money = money,costDiscount = 500 -- 消费满500有折扣} 
    -- 一个计算折扣的私有方法
    local checkDiscount = 
    function(cost)
        if cost > self.costDiscount then
          return 0.8
        else
          return 1
        end
    end
    -- 公共方法
    local shopping = 
    function(cost)
        self.money = self.money - cost*checkDiscount(cost)
    end
    local getMoney = function() return self.money end
    -- 返回一个供外界使用的接口
    return  {shopping = shopping,getMoney = getMoney }
end
    
local a = newCustomer(10000)
a.shopping(2000)
print(a.money) -- nil
print(a.getMoney())
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值