【问题标题】:In Lua, what is the difference between functions that use ":" and functions that do not? [duplicate]在 Lua 中,使用“:”的函数和不使用“:”的函数有什么区别? [复制]
【发布时间】:2014-12-21 23:40:21
【问题描述】:
假设我们有两个函数声明:
function MyData:New
end
和
function New(MyData)
end
它们之间有什么区别?在继承和 OOP 方面,使用: 有什么特殊用途吗?我只能使用: 调用使用: 声明的函数吗?
我是从只使用 C# 而来的——所以如果要进行任何比较,会是什么?
【问题讨论】:
标签:
function
inheritance
lua
arguments
【解决方案1】:
改编自manual, end of §3.4.10:
冒号语法用于定义方法,即具有隐式额外参数 self 的函数。因此,声明
function t:f (params) body end
是语法糖
t.f = function (self, params) body end
【解决方案2】:
您应该搜索 SO,因为有很多关于此的问题,但您有一系列问题,所以我不能说这是重复的。
问。它们之间有什么区别?
A. 冒号导致一个方法被添加到 MyData 表中,并且 Lua 解释器在调用时自动在第一个参数前插入一个“self”,这个“self”指向 MyData 实例,该“方法”正在被召唤。与写MyData.New = function(self) end 相同。第二个签名有一个名为MyData 的参数,是一个全局函数。它与 MyData 表(或类)无关。
问。在继承和 OOP 方面使用“:”有什么特殊用途吗?
答:没有;它只是语法糖,因此当您调用MyData.New 时,您可以只写MyData:New() 而不是看起来很笨重的MyData.New(MyData)。请注意,“新”函数通常用于创建类的实例,因此您不会将这样的函数作为方法,而只是 MyData 表中的函数。对于继承和 OOP,您使用元表,这不会以任何特殊方式与 : 交互。
问。我只能使用“:”调用用“:”声明的函数吗?
A. 不,如前所述,它只是语法糖,您可以定义一种方式并调用不同的方式。
问。我是从只使用 C# 而来的——所以如果要进行任何比较,那会是什么?
A. 对于函数, : 就像 .在 C# 中,无论是在调用还是定义中使用。这 ”。”在 Lua 中更像是“属性”,在 C# 中没有等价的函数。
MyData = {} -- a table
function MyData.func(self)
print('hello')
end
MyData:func()
MyData.func(MyData) -- same as previous
function MyData:func2() -- self is implicit
print('hello')
end
MyData:func2()
MyData.func2(MyData) -- same as previous
请注意,上面定义的 MyData 不是一个类,因为您不能创建它的“实例”(不做未在此处显示的额外工作)。一定要阅读 Lua.org 网站上的 Programming in Lua 在线书籍,其中有很多关于这些概念的有用讨论。
【解决方案3】:
Lua 本身没有函数声明;它具有函数定义表达式。您使用的语法是函数定义表达式和赋值的简写。
您的示例中的唯一区别是在执行第一条语句时,会创建一个新函数并将其分配给由变量 MyData 引用的表中的字段 New,而第二个是分配给非字段变量(本地,如果之前声明过,否则是全局的)。
请记住,这些只是对创建的函数值的第一次引用。像任何其他值一样,您可以将函数的引用分配给任何变量并将它们作为参数传递。
如果将形参用法添加到主体中,那么还有另一个区别:第一个有一个名为 self 的隐式第一个参数。
如果将函数调用添加到场景中,“:”语法将与左侧的表达式一起使用。它应该引用一个表。右边的标识符应该是该表中的一个字段,它应该引用一个函数。左表达式的值作为第一个实际参数传递给函数,其后有任何附加参数。
带有“:”的函数定义称为方法。带有“:”的函数调用称为方法调用。您可以使用任何您希望的函数调用语法构造对函数值的函数调用,该函数值是表中的一个字段,第一个参数是对表的引用。 Lua 方法定义和方法调用语法使它更容易,就好像函数是一个实例方法一样。这样,Lua 方法就像 C# 扩展方法。