首页 > 其他分享 >Lua 中的函数

Lua 中的函数

时间:2023-10-17 15:01:37浏览次数:39  
标签:10 f3 end 函数 -- Lua table local

# Lua 中的函数

image

基础形式

function Func (arg1, arg2)
	-- TODO
end
  • 不需要在定义的时候标注形参数据类型
  • 使用 end 作为结束
  • function 前可以使用 local 修饰,表示局部函数
  • function 作为公民可以被赋值给变量或当作参数传递
  • 一个 function 可以返回多个值

使用的时候也与其他语言没什么不同,但是有两个语法糖:

  1. 当参数只有一个且为 string 或 table 则可以省略圆括号
  2. 使用 :: 语法省略第一个参数
foo "Hello" -- 等价 foo ("Hello")
foo {name="ant", age=13} -- 等价 foo ({name="ant", age=13})

-- 下面两种方式等价,但只有在调用者本身作为第一个参数被传入的时候有效
obj.start (obj, port)
obj::start (port)

多值返回的接收

既然可以返回多个值,那么就可以接收多个值。但是 Lua 中对函数的多返回值比其他语言要灵活——并不需要全部接收。Lua 会自动适配,并接收对应的值。先看一个最简单的。

return 接收函数的所有返回值

local function f1()
  return 1, 2, 3
end

local function f2()
  return f1()
end

此处 f2 return 的是 f1 的执行结果,所以 return 会接收 f1 所有返回值(3 个)——其实就是简单的把其他函数的返回值当作自己的返回值返回。

多重赋值时候的自适应

如果一个函数的执行语句出现在赋值语句当中,那么他会像 Rust 的模式匹配一样自适应。让我看个例子来说明:

local function f3()
  return 1, 2, 3
end

local a = f3()               							-- 1 a = 1
local a, b = f3()            							-- 2 a = 1 b = 2
local a, b, c = f3()         							-- 3 a = 2 b = 2 c = 3
local a, b = f3(), 10        							-- 4 a = 1 b = 10
local a, b, c = f3(), 10     							-- 5 a = 1 b = 2 c = nil
local a, b, c = 10, f3()     							-- 6 a = 10 b = 1 c = 2
local a, b, c = 10, f3(), 20 							-- 7 a = 10 b = 1 c = 20
local a, b, c, d = 10, f3(), 20           -- 8 a = 10 b = 1 c = 20 d = nil

前三个挺好理解,f3 有 3 个返回值,a, b, c 从左到右去接收就是,多出来的就被抛弃。但是从第 4 个还是就有些魔幻了,我们一个一个来看。

起始第 4 个只需要猜分为 a = f3(), b = 10 两部分来看自然就清楚了,前一个式子就变成了第 1 个式子。第 7 个同理。那么第 5、6 呢?同样能够拆开,第 5 个拆为 a = f3()b = 10c = nil 。第 6 个拆为 a = 10b, c = f3() 这样来看是不是清楚了呢?

如果还有疑惑也不要慌。我们说过,这个自适应模式与 Rust 的模式匹配很相似。第 6 个式子左边有 3 个变量用于接收值,右边却只有两个式子提供了值,再一看 f3() 可以展开,所以就让 b ,c 和 f3 展开后的式子匹配。但是第 5 个应该也是相似的情况啊?因为单个的值具有优先选择权,他会限制 f3() 的展开,所以这个地方 f3()只能匹配到a,而无法匹配 a, b

再次强调,只是相似,不是相同。也就是说这是一种理解方式,而非底层原理。

这时候再来看下面两个语句是否立刻就理解了为何第一个式子不需要使用 _ 占位符了吧?

for key in pairs(t) do end
for key, value in pairs(t) do end

作为 table 元素

local t = { 10, f2() }       -- 10 1 2
local t = { f2(), 30 }       -- 1 30
local t = { f2(), 10, f2() } -- 1 10 1 2

在 table 中,也有且只有其作为最后一个元素的时候才会获得其所有值,其余情况,函数返回值列表并不会被展开,而是仅仅获得第一个。因此我们不难知道可以使用一个 table 去接收函数的所有返回值:

local result = {f3()}

因为在空 table 中 f3() 必定会成为最后一个元素。

table.unpack

在较早的 Lua 版本中,unpack 存存放在 _G 这个全局变量中,所以不需要使用 table. 就可以直接使用。

table.unpack 函数的作用是将一个列表的值逐一返回(nil 也会返回,不同于 pairs 和 ipairs,不过并不能用于 for 循环)。

print (table.unpack ({1, 2, 3, 4, 5, 6, 7}))
a, b, c = table.unpack ({1, 2, 3})
a, b, c = table.unpack ({f3()})

次数细看的话,就会发现其实还是在用 {} 去接收 f3 的返回值,而不是直接用的 table.unpack

小总结

起始上面所说的四点总结起来就是:只有当函数执行语句处于 return 语句,多重赋值的最后一个值、table最后一个元素的时候才能获得其返回的所有值。

变长参数

变长参数使用 ... 表示,且必须作为函数形参的最后一个参数。在使用的使用可以使用 pairs,ipairs,select 三种不同的方式。

-- 如果使用 ipairs 就会在遇到 nil 的时候终止,不再遍历后续元素
local function show1(...)
  for key, value in ipairs({ ... }) do
    print(value)
  end
end

-- 如果使用 pairs 则会跳过 nil 值
local function show2(...)
  for key, value in pairs({ ... }) do
    print(value)
  end
end

-- 如果 nil 作为有效值需要使用 select 进行遍历
local function show3(...)
  local len = select("#", ...)   -- select("#", ...) 可以获取 ... 的长度,此处不需要使用 {...}
  for i = 1, len, 1 do
    local value = select(i, ...) -- select(n, ...) 可以获取 ... 的第 n 个元素
    print(value)
  end
end

show1("hello", nil, "world") -- 输出: hello
show2("hello", nil, "world") -- 输出: hello world
show3("hello", nil, "world") -- 输出: hello nil world

具名参数

Lua 中并不存在如 C++ 或 Python 那样真正的具名参数,但是可以借助 table 来实现。

local function sayHello(man)
  print(man.name .. " say hello to " .. man.sbd)
end

-- 参数传递的时候使用 table 传递
sayHello({ name = "ant", sbd = "bnt" })

就是把参数”数组“变成参数”字典“——有没有让你想起 neovim 的配置文件?是的,这常常被用于处理一些可选参数/属性。

这与其说是具名参数,说是对 table 做参数传递的应用更加贴切。

把函数放入 table 的几种方式

函数作为一等公民,自然也可以像其他类型一样轻而易举的放入到 table 当中,想当然的方式自然就有下面几种方式

lib     = {
  f1 = function() end -- 方式一
}

lib.f2  = function() end -- 方式二

f3      = function() end
lib.f3  = f3 -- 方式三

但是 Lua 也提供了一种简便的写法:

function lib.f4() end

标签:10,f3,end,函数,--,Lua,table,local
From: https://www.cnblogs.com/ecila/p/17769707.html

相关文章

  • 无涯教程-NumPy - delete函数
    此函数返回一个新数组,其中指定的子数组已从数组中删除,与insert()函数一样,如果不使用axis参数,则将输入数组展平,该函数采用以下参数-Numpy.delete(arr,obj,axis)Sr.No.Parameter&描述1arr输入数组2obj可以是切片,整数或整数数组,指示要从输入数组中删除的子数组3......
  • 第六章 处理函数
    6.1数据处理函数(单行处理函数)函数名功能lower转换小写upper转换大写substr取子串(substr(被截取的字符串,起始下标,截取的长度)),注意:起始下标是1不是0length取长度trim去字符串首位空格str_to_date将字符串转换成日期date_format格式化日期format设置千分位round四舍五入rand()生成......
  • 无涯教程-NumPy - resize函数
    此函数返回具有指定大小的新数组,该函数采用以下参数。numpy.resize(arr,shape)Sr.No.描述1arr输入数组要调整大小2shape输出数组的新维度importnumpyasnpa=np.array([[1,2,3],[4,5,6]])print'Firstarray:'printaprint'\n'print'Theshapeo......
  • python中predict函数参数:如何使用Python的predict函数进行机器学习预测
    示例示例predict函数是scikit-learn中的一个函数,用于预测新样本的输出结果。参数:predict函数是scikit-learn中的一个函数,用于预测新样本的输出结果。参数:1.X:array-like或spmatrix,shape=[n_samples,n_features],测试样本,其中n_samples表示样本的数量,n_features表示特征的数量。2......
  • 函数的性质——奇偶性
    怎么判断一个函数的奇偶性?如果函数满足f(-x)=-f(x),则说明它是奇函数;如果函数满足f(-x)=f(x),则说明它是偶函数。举例说明:当函数满足f(-x)=-f(x)时,它是一个奇函数。一个简单的示例是函数f(x)=\(x^3\)。让我们验证一下:对于任意实数x,有f(-x)=\((-x)^3\)=\(-x......
  • 函数调用栈-执行上下文栈
    一调用栈我们知道栈的特点是,先进后出的。那么函数的执行上下文栈又是怎么样的呢?先看这段代码vara=2functionp2(b,c){returnb+c;}functionp1(b,c){vard=10;result=p2(b,c);returna+result+d;//2+9+10}console.log(p1(3,6));//21由于js代码是运行时编......
  • 【gdb】打印函数局部变量的值
    打印函数局部变量的值1.例子:#include<stdio.h>voidfun_a(void){ inta=0; printf("%d\n",a);}voidfun_b(void){ intb=1; fun_a(); printf("%d\n",b);}voidfun_c(void){ intc=2; fun_b(); printf("%d\n",c);......
  • 笨办法学Python3 习题35 分支和函数
    XX.isdigit()内置函数检验数据是否为数字类型 ifchoice<'50': #50需要加引号,不然报错 游戏内容:用函数定义4个房间,分别是开始的房间1,房间1左边的熊房间2,房间1右边的恶魔房间3,以及熊旁边的金币房间4。定义一个失败退出的函数。开始房间1进去选择走左边还是右边,用......
  • 无涯教程-NumPy - broadcast_to函数
    此功能将数组广播为新维度,它返回原始数组的只读视图,如果新维度不符合NumPy的广播规则,则该函数可能会引发ValueError。注意-此功能自版本1.10.0起可用。该函数采用以下参数。numpy.broadcast_to(array,shape,subok)importnumpyasnpa=np.arange(4).reshape(1,4)prin......
  • 函数指针变量
    函数指针变量函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调用函数intadd(intx,inty){ returnx+y;}intmain(){ printf("%p\n",&add); printf("%p\n",add); return0;}函数是有地址的,add的地址和&add的地址一致说明函数名就是函数的地址将函数的地址......