lua学习之函数篇 lua里面函数如何定义
liebian365 2024-10-29 15:53 23 浏览 0 评论
函数
- 函数是对语句和表达式进行抽象的主要机制
两种用法
- 一是可以完成特定的任务,一句函数调用被视为一条语句
- 二是以只用来计算并返回特定的结果,视为一句表达式
print("Hello, World")
a = math.sin(3) + math.cos(10)
print(os.date())
?
- 无论哪种用法都需要将所有参数放到一对圆括号中
- 但如果参数是字面字符串或 table 构造式的话,可以放在括号中,也可以不放
- 即使在调用函数时没有参数,也必须有一个 () 空括号,如调用 os.date()
print "Hello, World" -- 等价于 print("Hello, World")
print {1, 2, 3} -- 等价于 print({1, 2, 3})
?
function add(a)
local sum = 0
for i, v in ipairs(a) do
sum = sum + v
end
return sum
end
b = {1, 2, 3}
add(b)
- function 是定义函数的关键字
- add 是函数名
- a 是函数的形式参数,是函数定义式参数列表中的参数
- add(b) 调用这个函数所传入的参数称为实际参数
- 调用函数的实际参数的个数可以与函数定义时的形式参数个数不同
- lua 会自动调整实参的数量,以匹配参数表的要求,这和多s重赋值类似
- 若实参少于形参,多余的形参被初始化为 nil
- 若实参多余形参,多余的实参被抛弃
- lua 程序既可以使用 以 lua 编写的函数,也可使用 C 语言编写的函数
function f(a, b)
return a or b
end
f(3) -- a = 3, b = nil
f(3, 4) -- a = 3, b = 4
f(3, 4, 5) -- a = 3, b = 4 ,5 被丢弃了
定义一个全局的计数器
function intCount(n)
n = n or 1 -- 赋值一个默认值
count = count + 1
end
面向对象式调用函数
- o.foo(o, x)
- o:foo(x) 等价于 o.foo(o, x)
- 冒号操作符使得我们在调用 o.foo 时隐含地将 o 作为函数的第一个参数
多重返回值
- lua 允许函数返回多个结果
- 如标准库中的一些预定义函数
-- 用于在字符串中定位一个模式的函数 string.find
print(string.find("Hello Lua users", "Lua")) -- 开始的位置 7, 结束的位置 9
- 在 return 后列出需要返回的所有值即可,用 , 逗号分隔
-- 查找数组中的最大元素,并返回这个元素的所在位置
function maximum(a)
local mi = 1 -- 最大值的索引
local max = a[mi] -- 最大值
for i,v in ipairs(a) do
if v > max then
mi = i
max = v
end
end
return max, mi
end
maximum(a) -- 没有任何反应
print(maximum({3, 4, 23, 5, 7}) -- 23 3
print(maximum({3, 4, 23, 5, 7} .. "a") -- 23a
- 如果将函数调用作为单独的语句执行,lua 会丢弃所有的返回值
- 如果将将函数作为表达式的一部分调用,只保留函数的第一个返回值
- 只有当函数是一系列表达式中的最后一个元素(或只有一个元素的时候),才会获取所有的返回值
一系列表达式在 Lua 中的 4 中情况
- 多重赋值
- 函数调用时传入的实参列表
- table 构造式
- return 语句
多重赋值
- 在多重赋值中,如果一个函数调用是最后(或仅有)的一个表达式,lua 会保留尽可能多的返回值,用来匹配赋值的变量
- 如果一个函数没有返回值或没有返回足够多的返回值,那么 lua 会用 nil 来补充缺失的值
- 如果一个函数调用不是一系列表达式中的最后一个元素,就只能返回一个值
- 如果一个函数调用作为另一个函数调用的最后一个(或仅有的)实参的时候,第一个函数的所有返回值都会作为实参传递给另一个函数
function foo0() end
function foo1() return "a" end
function foo2() return "a", "b" end
-- 多重赋值的4种情况
-- 第一种情况
x, y = foo2() -- x = "a" , y = "b"
x = foo2() -- x = "a"
x, y, z = 10, foo2() -- x = 10, y = "a", z = "b"
-- 第二种情况
x, y = foo0() -- x = nil, y = nil
x, y = foo1() -- x = "a", y = nil
x, y, z = foo2() -- x = "a", y = "b", z = nil
-- 第三种情况
x, y = foo2(), 20 -- x = "a", y = 20
x, y = foo0(), 20, 30 -- x = nil, y = 20
-- 第四种情况
print(foo0()) -- 不会打印任何值
print(foo1()) -- a
print(foo2()) -- a, b
print(foo2(), 20) -- a, 1
print(foo2() .. "x") -- ax
table 构造式
- table 构造式可以完整地接收一个函数调用的所有结果,即不会有任何数量方面的调整
- 但这种行为,只有当一个函数调用作为最后一个元素时才会发生
- 其他位置上的函数调用总是只产生一个结果值
function foo0() end
function foo1() return "a" end
function foo2() return "a", "b" end
t = {foo2()} -- t = {"a", "b"}
t = {foo2(), "x"} -- t = {"a", "x"}
?
return
- 将函数调用放入一对圆括号 () 中,使其只返回一个结果
- return 语句后面的内容不需要 () 圆括号
- 如果强行加上则会使一个多返回值的函数,强制其只返回一个 return(f())
function foo0() end
function foo1() return "a" end
function foo2() return "a", "b" end
function foo(i)
if i == 0 then return foo0()
elseif i == 1 then return foo1()
elseif i == 2 then return foo2()
end
end
print(foo(1)) -- a
print(foo(2)) -- a, b
print(foo(0)) -- 无返回值
?
-- () 包裹
print((foo(1)) -- a
print((foo(2)) -- a
print((foo(0)) -- nil 不太懂为什么
unpack 函数
- 接收一个数组作为参数
- 并从下标 1 开始返回该数组的所有元素
- 这个预定义函数由 C 语言编写
print(unpack{10, 20, 30}) -- 10 20 30
a, b = unpack{10, 20, 30} -- a = 10, b = 20
- 用于泛型调用
- 泛型调用就是可以以任何实参来调用任何函数
-- 调用任意函数 f, 而所有的参数都在数组 a 中
-- unpack 将返回 a 中的所有值,这些值作为 f 的实参
f(unpack(a))
f = string.find
a = {"hello", "ll"}
f(unpack(a)) -- 3 4 等效于 string.find("hello", "ll")
用 lua 递归实现 unpack
function unpack(t, i)
i = i or 1
if t[i] then
return t[i], unpack(t, i + 1)
end
end
变长参数
- lua 中的函数可以接收不同数量的实参
- 当这个函数被调用时,它的所有参数都会被收集到一起
- 这部分收集起来的实参称为这个函数的「变长参数」
- ... 3个点表示该函数接收不同数量的实参
- 一个函数要访问它的变长参数时,需要用 ... 三个点,此时 ... 三个点是作为一个表达式使用的
- 表达式 ... 三个点的行为类似一个具有多重返回值的函数,它返回的是当前函数的所有变长参数
- 具有变长参数的函数也可以拥有任意数量的固定参数
- 但固定参数一定要在变长参数之前
- 当变长参数中包含 nil ,则需要用 select 访问变长参数
- 调用 select 时,必须传入一个固定参数 selector(选择开关) 和一系列变长参数
- 如果 selector 为数字 n ,那么 select 返回它的第 n 个可变实参
- 否则,select 只能为字符串 "#" ,这样 select 会返回变长参数的总数,包括 nil
-- 返回所有参数的和
function add(...)
local s = 0
for i, v in ipairs{...} do -- 表达式{...}表示一个由变长参数构成的数组
s = s + v
end
return s
end
print(add(3, 4, 5, 100)) -- 115
?
-- 调试技巧 ,类似与直接调用函数 foo ,但在调用 foo 前先调用 print 打印其所有的实参
function foo1(...)
print("calling foo:", ...)
return foo(...)
end
?
?
-- 获取函数的实参列表
function foo(a, b, c) end
function foo(...)
local a, b, c = ...
end
-- 格式化文本 string.format ,输出文本 io.write
-- 固定参数一定要在变长参数之前
function fwrite(fmt, ...)
return io.write(string.format(fmt, ...))
end
fwrite() -- fmt = nil
fwrite("a") -- fmt = a
fwrite("%d%d", 4, 5) -- fmt = "%d%d" , 变长参数 = 4, 5
?
for i = 1, select('#', ...) do
local arg = select('#', ...)
<循环体>
end
具名参数
- lua 中的参数传递机制是具有 「位置性」的
- 就是说在调用一个函数时,实参是通过它在参数表中的位置与形参匹配起来的
- 第一个实参的值与第一个形参相匹配,依此类推
- 定义:通过名称来指定实参
- 可将所有的实参组织到一个 table 中,并将这个 table 作为唯一的实参传给函数
- lua 中特殊的函数调用语法,当实参只有一个 table 构造式时,函数调用中的圆括号是可有可无的
os.rename -- 文件改名,希望达到的效果 os.rename(old = "temp.lua", new = "temp1.lua")
-- lua 不支持注释的写法
rename = {old = "temp.lua", new = "temp1.lua"}
function rename (arg)
return os.rename(arg.old, arg.new)
end
?
x = Window{x = 0, y = 0, width = 300, height = 200, title = "Lua", background = "blue", border = "true"}
?
-- Window 函数根据要求检查必填参数,或为某些函数添加默认值
-- 假设 _Window 是真正用于创建新窗口的函数,要求所有参数以正确次序传入
function Window(options)
if type(options.title) ~= "string" then
error("no title")
elseif type(options.width) ~= "number" then
error("no width")
elseif type(options.height) ~= "height" then
error("no height")
end
_Window(options.title,
options.x or 0 -- 默认值
options.y or 0 -- 默认值
options.width, options.height,
options.background or "white" -- 默认值
options.border -- 默认值为 false(nil)
)
相关推荐
- 精品博文嵌入式6410中蓝牙的使用
-
BluetoothUSB适配器拥有一个BluetoothCSR芯片组,并使用USB传输器来传输HCI数据分组。因此,LinuxUSB层、BlueZUSB传输器驱动程序以及B...
- win10跟这台计算机连接的前一个usb设备工作不正常怎么办?
-
前几天小编闲来无事就跑到网站底下查看粉丝朋友给小编我留言询问的问题,还真的就给小编看到一个问题,那就是win10跟这台计算机连接的一个usb设备运行不正常怎么办,其实这个问题的解决方法时十分简单的,接...
- 制作成本上千元的键盘,厉害在哪?
-
这是稚晖君亲自写的开源资料!下方超长超详细教程预警!!全文导航:项目简介、项目原理说明、硬件说明、软件说明项目简介瀚文智能键盘是一把我为自己设计的——多功能、模块化机械键盘。键盘使用模块化设计。左侧的...
- E-Marker芯片,USB数据线的“性能中枢”?
-
根据线缆行业的研究数据,在2019年搭载Type-C接口的设备出货量已达到20亿台,其中80%的笔记本电脑和台式电脑采用Type-C接口,50%的智能手机和平板电脑也使用Type-C接口。我们都知道,...
- ZQWL-USBCANFD二次开发通讯协议V1.04
-
修订历史:1.功能介绍1.1型号说明本文档适用以下型号: ZQWL-CAN(FD)系列产品,USB通讯采用CDC类实现,可以在PC机上虚拟出一个串口,串口参数N,8,1格式,波特率可以根据需要设置(...
- win10系统无法识别usb设备怎么办(win10不能识别usb)
-
从驱动入手,那么win10系统无法识别usb设备怎么办呢?今天就为大家分享win10系统无法识别usb设备的解决方法。1、右键选择设备管理器,如图: 2、点击更新驱动程序,如图: 3、选择浏览...
- 微软七月Win8.1可选补丁有内涵,含大量修复
-
IT之家(www.ithome.com):微软七月Win8.1可选补丁有内涵,含大量修复昨日,微软如期为Win7、Win8.1发布7月份安全更新,累计为6枚安全补丁,分别修复总计29枚安全漏洞,其中2...
- 如何从零开始做一个 USB 键盘?(怎么制作usb)
-
分两种情况:1、做一个真正的USB键盘,这种设计基本上不涉及大量的软件编码。2、做一个模拟的USB键盘,实际上可以没有按键功能,这种的需要考虑大量的软件编码,实际上是一个单片机。第一种设计:买现成的U...
- 电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题
-
电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题注意:有些方法会清除USB设备里的数据,请谨慎操作,如果不想丢失数据,可以先连接到其他电脑,看能否将数据复制出来,或者用一些数据恢复软件去扫...
- 未知usb设备设备描述符请求失败怎么解决
-
出现未知daousb设备设备描述符请求失du败解决办zhi法如下:1、按下Windows+R打开【运行】;2、在版本运行的权限输入框中输入:services.msc按下回车键打开【服务】;2、在服务...
- 读《飘》47章20(飘每章概括)
-
AndAhwouldn'tleaveMissEllen'sgrandchildrenfornotrashystep-patobringup,never.Here,Ah...
- 英翻中 消失的过去 37(消失的英文怎么说?)
-
翻译(三十七):消失的过去/茱迪o皮考特VanishingActs/JodiPicoult”我能做什么?“直到听到了狄利亚轻柔的声音,我才意识到她已经在厨房里站了好一会儿了。当她说话的时候,...
- RabbitMQ 延迟消息实战(rabbitmq如何保证消息不被重复消费)
-
现实生活中有一些场景需要延迟或在特定时间发送消息,例如智能热水器需要30分钟后打开,未支付的订单或发送短信、电子邮件和推送通知下午2:00开始的促销活动。RabbitMQ本身没有直接支持延迟...
- Java对象拷贝原理剖析及最佳实践(java对象拷贝方法)
-
作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的...
- 如何将 Qt 3D 渲染与 Qt Quick 2D 元素结合创建太阳系行星元素?
-
Qt组件推荐:QtitanRibbon:遵循MicrosoftRibbonUIParadigmforQt技术的RibbonUI组件,致力于为Windows、Linux和MacOSX提...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)