人们刚开始编程时,很快就会发现将所有代码写在一个大块中变得难以管理。因此,像 Lua 这样的现代编程语言支持一种称为函数的概念,它允许程序员指示程序的某些部分执行特定任务。除了编写清晰、有组织的代码之外,函数还是DRY(Don't Repeat Yourself,不要重复自己)概念的基础。
如果您发现自己多次编写相同的代码块,并且每个块只有细微的差异,那么使用函数是最佳解决方案。此外,任何时候您想要多次执行相同的操作,函数都是最佳方法。
让我们考虑一个场景,我们只需要围绕单个数据值更改一小部分代码
local tanx = math.abs( 12 ) / math.abs( 15 ) local atanx = math.atan( tanx ) -- Result in radians local angle = atanx * 180 / math.pi -- Converted to degrees print( angle ) tanx = math.abs( 34 ) / math.abs( -16 ) atanx = math.atan( tanx ) -- Result in radians angle = atanx * 180 / math.pi -- Converted to degrees print( angle ) tanx = math.abs( 80 ) / math.abs( -4 ) atanx = math.atan( tanx ) -- Result in radians angle = atanx * 180 / math.pi -- Converted to degrees print( angle )
在这个代码块中,我们只是根据三角形的宽度和高度计算角度。如您所见,这段代码很快变得重复——我们基本上是在一遍又一遍地做同样的事情,每次只改变三角形的参数。这是一个函数非常有用的典型例子,所以让我们看一下使用函数
local function calculateAngle( sideA, sideB ) local tanx = math.abs( sideB ) / math.abs( sideA ) local atanx = math.atan( tanx ) -- Result in radians local angle = atanx * 180 / math.pi -- Converted to degrees return angle end print( calculateAngle( 15, 12 ) ) print( calculateAngle( -16, 34 ) ) print( calculateAngle( -4, 80 ) )
请注意,我们只编写了一次基本代码,但我们使用变量sideA
和 sideB
)calculateAngle()
函数的 return
值(return
的用法将在下面详细讨论)。
数据作为参数发送给函数,或者一些开发人员称之为“参数”。它们作为函数括号 (()
) 内以
local picWidth = 32 local pic = display.newImageRect( "pic.png", picWidth, 64 )
在这个例子中,我们调用了一个常见的 Solar2D 函数 display.newImageRect()
,并向其传递
"pic.png"
)。picWidth
)。64
)。逗号之间的空格不是必需的,但字符串值必须在引号内传递,而变量和数字必须在不带引号的情况下传递。也可以传递其他项目,包括数据表,甚至是其他函数。本质上,任何有效的 Lua 数据类型都可以传递给 Lua 函数。
让我们看看更多例子
local result = myFunction( "test" )
local myString = "test" local result = myFunction( myString )
这两种情况的行为相同,只是在第二种版本中,唯一的参数是myString
。
这是另一个传入表格的等效集合
local result = myFunction( { 1, 2, 3 } )
local myTable = { 1, 2, 3 } local result = myFunction( myTable )
local myTable = {} myTable[1] = 1 myTable[2] = 2 myTable[3] = 3 local result = myFunction( myTable )
在这里,您可以看到完全相同的结果——一个包含一系列值的表格——被传递给 myFunction()
。您如何选择传入数据完全取决于您,它可能仅仅取决于您需要的灵活性。
如前所述,函数可以接受一种数据类型的参数或混合数据类型的参数。作为开发人员,您有责任确保传递给函数的值是您期望的值——不要粗心大意地传递字符串,而您希望它是数字,反之亦然
参数名称应该是对您有意义的任何名称——它们不需要是任何特定的名称。但是,如果您不使用逻辑完整的名字,以后检查您的代码的人(甚至您自己!)可能会难以理解函数期望什么值。让我们以触摸处理函数为例进行检查
local function handleTouch( event ) if ( event.phase == "ended" ) then -- Handle touch lifting off screen end return true end
此函数只需要一个参数 event
,它是一个表示用户触摸屏幕“事件”的 Lua 表。假设此函数通过如下命令用作侦听器函数Runtime:addEventListener( "touch", handleTouch )
请注意,一些程序员可能会编写如下相同的函数
local function handleTouch( e ) if ( e.phase == "ended" ) then -- Handle touch lifting off screen end return true end
这些函数的行为相同,只是参数名称 event
已缩短为 e
。虽然 e
不是描述性名称,但它表明名称本身并不重要——但是,最好明智地命名参数,这样您将来就不会忘记其用途。
通常,需要从函数中检索数据。在本教程的第一个示例中,我们需要根据传入的参数获取 angle
值。幸运的是,这可以通过简单的 return
命令轻松完成,后跟要返回的值
local function calculateAngle( sideA, sideB ) local tanx = math.abs( sideB ) / math.abs( sideA ) local atanx = math.atan( tanx ) -- Result in radians local angle = atanx * 180 / math.pi -- Converted to degrees return angle end
与大多数其他编程语言不同,Lua 允许函数返回多个值(其他语言通常只返回一个)。如果您需要从 Lua 函数返回多个值,只需提供一个return
的值列表,并在调用函数时为每个返回的值提供唯一的变量。比较区别
local function returnOneNumber() return 10 end local value = returnOneNumber()
local function returnTwoNumbers() return 10, 20 end local value1, value2 = returnTwoNumbers()
请注意,由于第二个函数返回两个值,因此逻辑上需要两个变量 value1
和 value2
来存储返回的值。
可以通过 Solar2D API myObject:getLinearVelocity()
直接观察到这种多返回值概念,这是一个检索物理对象当前线速度的物理函数。由于物理线速度始终由两个速度值组成,水平 (x) 和垂直 (y),因此通常像这样调用此函数
local linearVelocityX, linearVelocityY = myObject:getLinearVelocity()
但是请注意,您不需要将所有返回的值存储为单独的变量。例如,如果您只关心物理对象的线性x速度,则只存储该值,线性y值将被丢弃
local linearVelocityX = myObject:getLinearVelocity()
有时函数可能需要接受可变数量的参数。Lua 使用可变参数 ...
语法来适应这种情况。考虑以下函数,它接受数量不确定的数值参数并将它们加在一起成为一个总和
local function addNumbers( ... ) local sum = 0 for i = 1,#arg do sum = sum + arg[i] end return sum end local finalSum = addNumbers( 1, 12, 4, 5, 2 ) print( finalSum )
在这里,请注意 Lua 如何使用三个连续的句点 (...
) 来表示数量不等的参数,并且一旦进入函数内部,这将生成一个名为 arg
的表,它是一个
local function addNumbers( ... ) local sum = 0 for i = 1,#arg do sum = sum + arg[i] end return sum end
希望本教程能够帮助您理解函数的性质、它们的巨大用途、如何将不同类型的数据传递给函数,以及如何检索所需的信息。请记住,清晰的编码和巧妙地使用函数将改进应用程序的结构和性能,并使程序代码更易于理解。