• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >Lua > Lua中类的实现原理探讨(Lua中实现类的方法)

Lua中类的实现原理探讨(Lua中实现类的方法)

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了lua 类,lua 类如何设计成单例,lua 类继承,lua 创建一个类,lua类的实现等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Lua中没有类的概念,但我们可以利用Lua本身的语言特性来实现类。

下文将详细的解释在Lua中实现类的原理,涉及到的细节点将拆分出来讲,相信对Lua中实现类的理解有困难的同学将会释疑。

类是什么?

想要实现类,就要知道类到底是什么。

在我看来,类,就是一个自己定义的变量类型。它约定了一些它的属性和方法,是属性和方法的一个集合。

所有的方法都需要一个名字,即使是匿名函数实际上也有个名字。这就形成了方法名和方法函数的键值映射关系,即方法名为键,映射的值为方法函数。

比如说有一个类是人,人有一个说话的方法,那就相当于,人(Person)是一个类,说话(talk)是它的一个方法名,说话函数是它的实际说话所执行到的内容。

人也有一个属性,比如性别,性别就是一个键(sex),性别的实际值就是这个键所对应的内容。

理解了类实际上是一个键值对的集合,我们不难想到用Lua中自带的表来实现类。

实例是什么?

如果理解了类实际就是一个键值映射的表,那么我们再来理解实例是什么。

实例就是具有类的属性和方法的集合,也是一个表了。听起来好像和类差不多?

类全局只有一个集合,相当于上帝,全局只有一块内存;而实例就普通了,普天之下有那么多人,你可以叫A说一句话,A便执行了他的说话方法,但是不会影响B的说话。因为他们是实例,彼此分配着不同的内存。

说了那么多废话,其实实例就是由类创建出来的值,试着把类想象成类型而不是类。

两个语法糖

试着创建一个人类 Person

Person = {name="这个人很懒"}
</div>

以上代码将Person初始化为一个表,这个表拥有一个为name的键,其默认值是"这个人很懒"。

说成白话就是人类拥有一个叫名字的属性。

那就再赋予人类一个说话的功能吧。

Person.talk = function(self, words)
    print(self.name.."说:"..words)
end
</div>
以上代码在Person表中加入一个键值对,键为talk,值为一个函数。

好了,只要调用,Person.talk(Person, "你好"),将会打印出:这个人很懒说:你好。

不过在写程序时,大家都习惯把function放在前面,这就是函数的语法糖:

function Person.talk(self, words)
    print(self.name.."说:"..words)
end
</div>
这与上面的函数定义是等价的,但是这么写你就很难看出来talk其实是Person表中的一个键,其对应的值为一个函数。

当然嘴巴都是长在自己身上的,说话只能自己说,不可能自己张嘴别人说话,所以每次都传个self参数实在是有点不美观,于是冒号语法糖上场。

我们还可以这么定义人类的说话功能:

function Person:talk(words)
    print(self.name.."说:"..words)
end
</div>
这与上面两段代码都是等价的,它的变化是少了self的参数,将点Person.talk改为了冒号Person:talk。

但是函数体内,却依然可以使用self,在使用:代替.时,函数的参数列表的第一个参数不再是words,Lua会自动将self做为第一个参数。这个self参数代表的意思就是这个函数的实际调用者。

所以我们调用Person:talk("你好")与Person.talk(Person, "你好")是等价的,这就是冒号语法糖带来的便利。

如何查找表中的元素?

下面我们需要理解在Lua的表中是怎么查找一个键所对应的值的。

假设我们要在表p中查找talk这个键所对应的值,请看下面的流程图:
p中有没有talk这个键? 有 --> 返回talk对应的值
        |
       没有
        |
p中是否设置过metatable? 否 -->  返回nil
        |
        有
        |
在p的metatable中有没有__index这个键? 没有 -->  返回nil
        |
        有
        |     
在p的metatable中的__index这个键对应的表中有没有talk这个键? 没有 --> 返回nil
        |
        有,返回getmetatable(p).__index.talk
</div>

理解以上内容是本文的重点,反复阅读直至你记住了。

可以看到,由于metatable和__index这两个神奇的东西,Lua能在当前表中不存在这个键的时候找到其返回值。

下面将会讲一讲metatable这个语言特性。

对metatable的理解

metatable是什么?

metatable的中文名叫做元表。它不是一个单独的类型,元表其实就是一个表。

我们知道在Lua中表的操作是有限的,例如表不能直接相加,不能进行比较操作等等。

元表的作用就是增加和改变表的既定操作。只有设置过元表的表,才会受到元表的影响而改变自身的行为。

通过全局方法setmetatable(t, m),会将表t的元表设置为表m。通过另一个全局方法getmetatable(t)则会返回它的元表m。

注意:所有的表都可以设置元表,然而新创建的空表如果不设置,是没有元表的。

元方法

元表作为一个表,可以拥有任意类型的键值对,其真正对被设置的表的影响是Lua规定的元方法键值对。

这些键值对就是Lua所规定的键,比如前面说到的__index,__add,__concat等等。这些键名都是以双斜杠__为前缀。其对应的值则为一个函数,被称为元方法(metamethod),这些元方法定义了你想对表自定义的操作。

例如:前面所说的__index键,在Lua中它所对应的元方法执行的时机是当查找不存在于表中的键时应该做的操作。考虑以下代码:
--定义元表m
m = {}
--定义元表的__index的元方法
--对任何找不到的键,都会返回"undefined"
m.__index = function ( table, key )
  return "undefined"
end  
 
--表pos
pos = {x=1, y=2}
--初始没有元表,所以没有定义找不到的行为
--因为z不在pos中,所以直接返回nil
print(pos.z) -- nil
--将pos的元表设为m
setmetatable(pos, m)
--这是虽然pos里仍然找不到z,但是因为pos有元表,
--而且元表有__index属性,所以执行其对应的元方法,返回“undefined”
print(pos.z) -- undefined
</div>

pos表中本没有z这个键,通过设置pos的元表为m,并设置m的__index对应的方法,这样所有取不到的键都会返回“undefined”了。

以上我们了解到,元表的__index属性实际上是给表配备了找不到键时的行为。

注意:元表的__index属性对应的也可以为一个表。

再举个栗子,希望能够加深对元表和元方法的理解,__add键,考虑以下代码:
--创建元表m,其中有__add键和其定义的方法
local m = {
  __add = function(t1, t2)
    local sum = {}
    for key, value in pairs(t1) do
    &nbs

您可能想查找下面的文章:

  • Lua中基本的数据类型、表达式与流程控制语句讲解
  • Lua中的类编程代码实例
  • Lua中模块以及实现方法指南
  • Lua实现类继承
  • Lua数据类型介绍
  • Lua中类的实现原理探讨(Lua中实现类的方法)

相关文章

  • Lua中的函数写法简明示例
  • Lua中的函数知识总结
  • Lua实现split函数
  • Ruby元编程技术详解(Ruby Metaprogramming techniques)
  • lua实现的2048小游戏
  • Lua5.1中加载dll动态链接库的方法
  • Lua中的函数浅析
  • Lua教程(十七):C API简介
  • Lua中获取table长度问题探讨
  • Lua脚本实现递归删除一个文件夹

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • Lua中的函数知识总结
    • Lua中获取table长度问题探讨
    • Lua中if语句嵌套的使用教程
    • Lua中的metatable详解
    • Lua中类的实现
    • Lua中的全局变量、非全局变量总结
    • Linux下编写Lua扩展so文件和调用方法实例
    • lua中赋值类型代码详解
    • Lua的内存管理浅析
    • Lua编程中使用嵌套循环的使用教程

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有