可变数量的函数参数Lua 5.1

时间:2011-09-27 17:57:28

标签: lua

在我的Lua脚本中,我正在尝试使用可变数量的参数创建一个函数。据我所知它应该像下面这样工作,但不知怎的,我在TI-NSpire上得到了Lua 5.1的错误(全局arg是零)。我究竟做错了什么?谢谢!

function equation:init(...)
    self.equation = arg[1]
    self.answers = {}
    self.pipe = {arg[1]}
    self.selected = 1

    -- Loop arguments to add answers.
    for i = 2, #arg do
        table.insert(self.answers, arg[i])
    end
end

instance = equation({"x^2+8=12", -4, 4})

2 个答案:

答案 0 :(得分:36)

Luis's answer是正确的,如果比语言的初学者更苛刻可能希望。我会尝试详细说明一下,希望不会产生额外的混淆。

您的问题是在嵌入TI计算器特定模型的Lua环境中。因此,有些细节与独立的Lua不同,但大多数细节都与您的环境中可用的库和函数有关。 Lua的嵌入式版本与其作者分发的独立Lua有很大不同,这是不寻常的(虽然因为Lua是开源的,可能)。 (Lua Binaries是许多平台的二进制文件库。Lua for Windows是一个包含电池的Windows完整发行版。)

您的示例代码有一个混淆因素,它需要与计算器框架提供的类系统进行交互。该细节主要表现为您的equation对象与被调用的equation:init()函数之间缺少连接。由于有些技术可以将其粘合起来,这只是一种分心。

我理解的问题可归结为关于如何在Lua中声明和实现可变函数(具有可变数量的参数的函数)的混淆。根据你对路易斯答案的评论,你一直在阅读Lua编程的网络版(又名PiL)。你引用了section 5.2。 PiL是该语言背景的良好来源。不幸的是,可变函数是一直在变化的特征之一。从Lua 5.0版起,该书的在线版本是正确的,但TI计算器可能正在运行Lua 5.1.4。

在Lua 5中,使用参数列表声明可变参数函数,该参数列表以符号...结尾,代表其余参数。在Lua 5.0中,调用是使用名为arg的“魔术”局部变量实现的,该变量包含一个包含与...匹配的参数的表。这要求每个可变参数函数在调用时创建一个表,这是垃圾收集器不必要的开销和压力的来源。所以在Lua 5.1中,实现发生了变化:...可以直接在被调用函数中用作匹配参数的别名,但实际上并没有创建表。相反,如果需要参数计数,则编写select("#",...),如果需要第n个参数的值,则编写select(n,...)

您示例中的混淆因素会回到类系统。您想声明函数equation:init(...)。由于此声明使用冒号语法,因此它等同于编写equation.init(self,...)。因此,当最终通过类框架使用__call元方法调用时,真正的第一个参数名为self,零个或多个实际参数将匹配...

正如下面Amr的评论所指出的,表达式select(n,...)实际上返回了第n个参数的所有值,这在构造self.answers的情况下特别有用,但也会导致可能的错误在初始化self.pipe

以下是我在equation:init()定义中尝试实现的修正近似值,但请注意我手边没有TI计算器,这是未经测试的:

function equation:init(...)
    self.equation = select(1, ...)
    self.pipe = { (select(1,...)) }
    self.selected = 1
    self.answers = { select(2,...) }
end

在上面显示的修订版本中,我编写了{(select(1,...))}来创建一个只包含一个元素的表,这个元素是第一个参数,而{select(2,...)}创建一个包含所有剩余参数的表。虽然以这种方式可以插入表中的值的数量有限,但该限制与函数的返回值的数量或可以传递给函数的参数的数量有关,因此不能超过...的引用。请注意,这可能不是一般的情况,并且编写{ unpack(t) } 会导致不复制t的所有数组部分。

编写函数的效率稍低一点就是在传递的参数上写一个循环,这是我原来答案中的版本。这看起来如下:

function equation:init(...)
    self.equation = select(1, ...)
    self.pipe = {(select(1,...))}
    self.selected = 1

    -- Loop arguments to add answers.
    local t = {}
    for i = 2, select("#",...) do
        t[#t+1] = select(i,...)
    end
    self.answers = t
end

答案 1 :(得分:24)

尝试

function equation:init(...)
     local arg={...}