在Lua编程中,经常会看到有时用点号定义一个table的成员函数,有时却用冒号,在调用的时候也是如此。那么点号和冒号在使用上有什么区别呢?它们与self之间又是什么样的关系呢?稍安勿躁,接下来谜底将一一为你揭开。

下面先看一个例子

Class = {}
Class.__index = Class function Class.new(x,y)
local cls = {}
setmetatable(cls, Class)
cls.x = x
cls.y = y
return cls
end
function Class:test()
-- 等价于
-- function Class.test(self)
print(self.x,self.y)
end object = Class.new(10,20) object:test() --10 20
-- 等价于
object.test(object) --10 20

可以看到:

(1)定义的时候:Class:test()与 Class.test(self)是等价的;

(2)调用的时候:object:test() 与object.test(object)等价。

但是,一定要小心了,如果我们把例子中代码做一个小小的改动:

object = Class.new(10,20)

改为

object = Class:new(10,20)

猜一下最终的输出结果是什么?

最终的输出结果:

table: 00FFE788 10

table: 00FFE788 10

你是不是大吃一惊了,输出的结果跟我们的预期完全就是天壤之别。那为什么会得到这样的输出结果呢?深层次的原因是什么?下面一一道来。

在这里,我们在调用的时候将点号改为了冒号,使用冒号时,会隐性传递一个self参数,它表示的是调用对象,这样一来,Class:new(10, 20)这样的函数调用实际上有3个实参,分别是self,10,20,但是function Calss.new(x, y)这样用点号实现的函数定义实际上只有2个形参,这样传参的结果是

self ——> x

10 ——> y

20 ——> 丢弃

因此,最终我们打印出来的x和y的值就是self和10,而self实际就是table Class。如果我们把Class.new方法稍微修改一下如下:

function Class.new(self, x,y)

local cls = {}

setmetatable(cls, Class)

cls.x = x

cls.y = y

return cls

end

或者改为

function Class:new(x,y)

local cls = {}

setmetatable(cls, Class)

cls.x = x

cls.y = y

return cls

end

那么最终输出结果将会是我们预期的:

10 20

10 20

通过上述分析,我们可以看到,点号和冒号最主要的区别在于是否包含隐性参数self,使用冒号格式定义或调用函数方法时,Lua会默认把调用者对象隐藏起来了,虽然隐藏起来了,但是我们却不能忽略它的存在性,不管你相信不相信,它就在那里,不左不右。而使用点号格式定义或调用函数方法时,所有参数都是被显示地声明的,不会躲躲藏藏,有多少就是多少,因此,如果我们需要传递调用者对象,那么必须显示声明之。

下面来看几个例子

例1

a = { x = 1 }
function a.fun(self) 
  print(self.x)
end

a.fun(a)        --输出1,将a自己做为参数传给fun函数的self

通过点号格式定义fun,并且通过点号调用函数fun。定义时显示给出self形参用于接收调用者对象;调用时必须显示给出调用者对象作为实参传入。

例2

function a:fun() 
    print(self.x)
end

a.fun(a)

通过冒号格式定义fun,并且通过点号调用fun。定义时隐藏了形参self,虽然我们看不到,但是self是客观存在的,因此,在函数内部我们可以直接使用self;调用时显示给出调用者对象作为实参传入。

例3

function a:fun() 
    print(self.x)
end

a:fun()

通过冒号格式定义和调用fun。定义时隐藏了形参self,调用时也隐藏了调用者对象这个实参,虽然我们看不到,但是a这个实参确确实实是被传递给了self。

上面讨论的都是函数方法的定义和调用,那么对于非函数的数据成员又是怎么样的呢?对于数据成员的访问我们是否也是可以通过冒号或点号的形式来完成呢?很遗憾地告诉你,答案是否定的。

看一个例子

girl = {money = 200}

function girl.goToMarket(girl ,someMoney)
   girl.money = girl.money - someMoney
end

girl.goToMarket(girl ,100)
print(girl.money)

输出结果

100

girl = {money = 200}
function girl.goToMarket(girl ,someMoney)
   girl.money = girl.money - someMoney
end
girl.goToMarket(girl ,100)
print(girl:money)

输出结果

error:function arguments expected near ')'

通过上面例子可以看到,对于非成员函数的数据成员的访问,可以用点号的形式,但是不能用冒号的形式。

综上所述,给出一条不成文的约定:

用lua进行面向对象的编程,成员方法的声明和调用统一用冒号形式,对于数据成员的调用全部用点号形式。

LUA中的冒号、点和self的更多相关文章

  1. lua 中的点、冒号与self

    [lua 中的点.冒号与self] lua编程中,经常遇到函数的定义和调用,有时候用点号调用,有时候用冒号调用. girl = {money = 200} function girl.goToMark ...

  2. Lua中的点、冒号与self

    Lua中的点.冒号与self,它们之间的关系主要体现在函数的定义与调用上,Lua在函数定义时可以用点也可以用冒号,如: function mytable.fun(p) return p end fun ...

  3. lua中的面向对象编程

    简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 上述代码会输出tb1 ~= tb2.说明两个具有相同值得对象是两个不同的对象,同时在Lua中table是引用类型的 ...

  4. Lua中的一些库(1)

    [数学库] 数学库(math)由一组标准的数学函数构成.这里主要介绍几个常用的函数,其它的大家可以自行百度解决. 三角函数(sin,cos,tan……)所有的三角函数都使用弧度单位,可以用函数deg( ...

  5. <6>Lua元表和冒号 self

    Lua中没有像C.C++.JAVA中的类概念,面向对象等 ,但我们可以模拟出来 1. Lua中有个很重要的概念元表 设置元表setmetatable()函数  获取元表getmetatable()函数 ...

  6. 理解lua中 . : self

    前言 在LUA中,经常可以看到:. self,如果你学习过Java或C#语言,可以这样理解 .对于c#和java的静态方法 :相当于是实例方法 今天在CSDN上看到一篇博客写的很清楚,转载过来 原文出 ...

  7. Lua中“.”调用方法与“:”调用方法的区别

    Lua中“.”调用方法与“:”调用方法的区别:                                                                             ...

  8. 【转载】Lua中实现类的原理

    原文地址 http://wuzhiwei.net/lua_make_class/ 不错,将metatable讲的很透彻,我终于懂了. --------------------------------- ...

  9. Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween

    在上一篇文章 Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 中,我对LuaBehaviour脚本进行了扩展,添加了两个新的UI监听方法,也提到最好能单写一个脚本处理此 ...

随机推荐

  1. 自定义alert 确定、取消功能

    以删除为例,首先新建html <table border="1" cellpadding="0" cellspacing="0" id ...

  2. IntelliJ + Maven + 内Jetty 实现热部署项目

    部署的好处:代码修改后,不必关闭Jetty再重新启动,Maven启动时间不太和谐. 环境: IntelliJ IDEA11.1.4, Maven2.2.1 Jetty8.1.5 步骤: 1,在pom. ...

  3. C# sort System.InvalidOperationException: Failed to compare two elements in the ar

    System.InvalidOperationException: Failed to compare two elements in the array. ---> System.NullRe ...

  4. Perl 数组应用详解(push, pop, shift, unshift)

    Perl的数组操作有四大常用函数: push:从数组的末尾加入元素.pop :从数组的末尾取出元素 shift: 从数组的开头取出元素unshift:从数组的开头加入元素 1.push #!/usr/ ...

  5. word 文献标题自动编号

    来自:word中自动编号和多级编号的使用 选中标题或段落,点击鼠标右键,在编号菜单内选择适合的自动编号样式.或者在窗口上方的“开始”选项卡中选择编号样式.如果对已选的编号样式不满意,可以照以上方法直接 ...

  6. LightOJ-1282-Leading and Trailing-快速幂+数学

    You are given two integers: n and k, your task is to find the most significant three digits, and lea ...

  7. jwt、oauth2和oidc等认证授权技术的理解

    前言 jwt.oauth2.oidc等,都是和认证授权相关的规范或者解决方案,因此要理解他们,就需要从业务场景的适用性一步步的分析和认识. 一.认证授权业务场景理解 就个人目前的理解来看,一个好的软件 ...

  8. 9.ActiveMQ理论

    一.首先说下什么是消息队列? 1.消息队列是在消息的传输过程中保存消息的容器. 二.为什么要用到消息队列? 主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的inse ...

  9. MySQL 05章_模糊查询和聚合函数

    在之前的查询都需要对查询的关机中进行“精确”.“完整”完整的输入才能查询相应的结果, 但在实际开发过程中,通常需要考虑用户可能不知道“精确”.“完整”的关键字, 那么就需要提供一种不太严格的查询方式, ...

  10. OC开发系列-@property和@synthesize

    property和synthesize 创建一个Person类.提供成员属性的_age和_height的setter和getter方法. #import <Foundation/Foundati ...