函数

  1. 函数是对语句和表达式进行抽象的主要机制

两种用法

  1. 一是可以完成特定的任务,一句函数调用被视为一条语句
  2. 二是以只用来计算并返回特定的结果,视为一句表达式
print("Hello, World")
a = math.sin(3) + math.cos(10)
print(os.date())
  1. 无论哪种用法都需要将所有参数放到一对圆括号中
  2. 但如果参数是字面字符串或 table 构造式的话,可以放在括号中,也可以不放
  3. 即使在调用函数时没有参数,也必须有一个 () 空括号,如调用 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)
  1. function 是定义函数的关键字
  2. add 是函数名
  3. a 是函数的形式参数,是函数定义式参数列表中的参数
  4. add(b) 调用这个函数所传入的参数称为实际参数
  5. 调用函数的实际参数的个数可以与函数定义时的形式参数个数不同
  6. lua 会自动调整实参的数量,以匹配参数表的要求,这和多s重赋值类似
  7. 若实参少于形参,多余的形参被初始化为 nil
  8. 若实参多余形参,多余的实参被抛弃
  9. 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

面向对象式调用函数

  1. o.foo(o, x)
  2. o:foo(x) 等价于 o.foo(o, x)
  3. 冒号操作符使得我们在调用 o.foo 时隐含地将 o 作为函数的第一个参数

多重返回值

  1. lua 允许函数返回多个结果
  2. 如标准库中的一些预定义函数
-- 用于在字符串中定位一个模式的函数 string.find
print(string.find("Hello Lua users", "Lua")) -- 开始的位置 7, 结束的位置 9
  1. 在 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
  1. 如果将函数调用作为单独的语句执行,lua 会丢弃所有的返回值
  2. 如果将将函数作为表达式的一部分调用,只保留函数的第一个返回值
  3. 只有当函数是一系列表达式中的最后一个元素(或只有一个元素的时候),才会获取所有的返回值

一系列表达式在 Lua 中的 4 中情况

  1. 多重赋值
  2. 函数调用时传入的实参列表
  3. table 构造式
  4. return 语句

多重赋值

  1. 在多重赋值中,如果一个函数调用是最后(或仅有)的一个表达式,lua 会保留尽可能多的返回值,用来匹配赋值的变量
  2. 如果一个函数没有返回值或没有返回足够多的返回值,那么 lua 会用 nil 来补充缺失的值
  3. 如果一个函数调用不是一系列表达式中的最后一个元素,就只能返回一个值
  4. 如果一个函数调用作为另一个函数调用的最后一个(或仅有的)实参的时候,第一个函数的所有返回值都会作为实参传递给另一个函数
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 构造式

  1. table 构造式可以完整地接收一个函数调用的所有结果,即不会有任何数量方面的调整
  2. 但这种行为,只有当一个函数调用作为最后一个元素时才会发生
  3. 其他位置上的函数调用总是只产生一个结果值
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

  1. 将函数调用放入一对圆括号 () 中,使其只返回一个结果
  2. return 语句后面的内容不需要 () 圆括号
  3. 如果强行加上则会使一个多返回值的函数,强制其只返回一个 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. 接收一个数组作为参数
  2. 并从下标 1 开始返回该数组的所有元素
  3. 这个预定义函数由 C 语言编写
print(unpack{10, 20, 30}) -- 10 20 30
a, b = unpack{10, 20, 30} -- a = 10, b = 20
  1. 用于泛型调用
  2. 泛型调用就是可以以任何实参来调用任何函数
-- 调用任意函数 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

变长参数

  1. lua 中的函数可以接收不同数量的实参
  2. 当这个函数被调用时,它的所有参数都会被收集到一起
  3. 这部分收集起来的实参称为这个函数的「变长参数」
  4. ... 3个点表示该函数接收不同数量的实参
  5. 一个函数要访问它的变长参数时,需要用 ... 三个点,此时 ... 三个点是作为一个表达式使用的
  6. 表达式 ... 三个点的行为类似一个具有多重返回值的函数,它返回的是当前函数的所有变长参数
  7. 具有变长参数的函数也可以拥有任意数量的固定参数
  8. 但固定参数一定要在变长参数之前
  9. 当变长参数中包含 nil ,则需要用 select 访问变长参数
  10. 调用 select 时,必须传入一个固定参数 selector(选择开关) 和一系列变长参数
  11. 如果 selector 为数字 n ,那么 select 返回它的第 n 个可变实参
  12. 否则,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

具名参数

  1. lua 中的参数传递机制是具有 「位置性」的
  2. 就是说在调用一个函数时,实参是通过它在参数表中的位置与形参匹配起来的
  3. 第一个实参的值与第一个形参相匹配,依此类推
  4. 定义:通过名称来指定实参
  5. 可将所有的实参组织到一个 table 中,并将这个 table 作为唯一的实参传给函数
  6. 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)
)

lua学习之函数篇的更多相关文章

  1. Lua 学习之基础篇二<Lua 数据类型以及函数库 汇总>

    引言 前面讲了运算符,这里主要对Lua的数据处理相关的数据类型和函数库进行总结归纳,后面会再接着单独分开讲解具体使用. 首先因为Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值. 值可以存储 ...

  2. Lua学习(4)——函数

    在Lua中函数的调用方式和C语言基本相同,如:print("Hello World")和a = add(x, y).唯一的差别是,如果函数只有一个参数,并且该参数的类型为字符串常量 ...

  3. lua学习之表达式篇

    表达式 表达式用于表达值 lua 中表达式可以为数字常量,自变字符串,变量,一元和二元操作符,函数调用.函数定义.table 构造式 算数操作符 一元操作符 -负号 二元操作符 -减号 / ^ % x ...

  4. Lua 学习之基础篇十<Lua 常见的语法规则>

    下面讲一些lua 常见的用法和规则,可以为学习理解lua带来帮助,最后附上的部分是lua的基本操作,基本包含所有常用语法语句. 1. if判断 lua把 nil 和false 视为"假&qu ...

  5. Lua 学习之基础篇七<Lua Module,Package介绍>

    Lua 之Module介绍 包管理库提供了从 Lua 中加载模块的基础库. 只有一个导出函数直接放在全局环境中: [require]. 所有其它的部分都导出在表 package 中. require ...

  6. Lua 学习之基础篇九<Lua 协同程序(Coroutine)>

    引言 讲到协程,首先来介绍一下线程和协程的区别 lua协程和多线程 相同之处:拥有自己独立的桟.局部变量和PC计数器,同时又与其他协程共享全局变量和其他大部分东西 不同之处:一个多线程程序可以同时运行 ...

  7. Lua 学习之基础篇八<Lua 元表(Metatabble)&&继承>

    讲到元表,先看一段table的合并动作. t1 = {1,2} t2 = {3,4} t3 = t1 + t2 attempt to perform arithmetic on a table val ...

  8. Lua 学习之基础篇六<Lua IO 库>

    引言 I/O 库提供了两套不同风格的文件处理接口. 第一种风格使用隐式的文件句柄: 它提供设置默认输入文件及默认输出文件的操作, 所有的输入输出操作都针对这些默认文件. 第二种风格使用显式的文件句柄. ...

  9. Lua 学习之基础篇五<Lua OS 库>

    lua os库提供了简单的跟操作系统有关的功能 1.os.clock() 返回程序所运行使用的时间 local nowTime = os.clock() print("now time is ...

随机推荐

  1. Redhat6 RPM 软件管理常用命令汇总

    软件的安装时操作系统管理的基础,与Windows不同,Linux的软件管理有很多种方式,Redhat的最常用的是RPM方式,安装集成在光盘中的RPM包.这种方式比Windows平台的软件管理更加便捷( ...

  2. JUnit 5和Selenium基础(三)

    在这一部分教程中,将介绍JUnit 5的其他功能,这些功能将通过并行运行测试,配置测试顺序和创建参数化测试来帮助减少测试的执行时间.还将介绍如何利用Selenium Jupiter功能,例如通过系统属 ...

  3. 用python搭一个超简易的文件服务器

    这个文件服务器纯粹是在学习python cgi编程时,顺便玩玩而已,因为搭文件服务器的话完全可以linux,简单方便,这里就是随便玩玩,功能也就是只能下载文件 1.登录页面,做个简单验证 新建一个ht ...

  4. 使用rabbitmq手动确认消息的,定时获取队列消息实现

    描述问题 最近项目中因为有些数据,需要推送到第三方系统中,因为数据会一直增加,并且需要与第三方系统做相关交互. 相关业务 本着不影响线上运行效率的思想,我们将增加的消息放入rabbitmq,使用另一个 ...

  5. 通过核心API启动单个或多个scrapy爬虫

    1. 可以使用API从脚本运行Scrapy,而不是运行Scrapy的典型方法scrapy crawl:Scrapy是基于Twisted异步网络库构建的,因此需要在Twisted容器内运行它,可以通过两 ...

  6. 配置IDEA默认作者@author

    IDEA安装目录下,使用文本编辑器打开~/bin/idea64.exe.vmoptions文件 在最后添加:-Duser.name=Your name 保存重启IDEA,Done

  7. 【C_Language】---队列和栈的C程序实现

    这几天总结了C语言的队列,栈的实现方法,在此总结一下:一.栈 首先从栈开始,诚然,相信学习过数据结构的你,肯定应该知道栈是什么东西了,如果不知道也没事每一句话我就可以帮你总结--数据只在栈顶进行插入和 ...

  8. Python解析json字符串,json字符串用法

    json数据简介 json数据是一个轻量级的数据交换格式,采用完全独立于语言的文本格式,这些特性使json称为理想的数据交换语言,易于人阅读和编写,同时易于机器解析和生成. json中的字符集必须是U ...

  9. Gitlab的介绍

    什么是GitLab ?◆GitLab是一个开源分布式版本控制系统◆开发语言: Ruby◆功能:管理项目源代码.版本控制.代码复用与查找GitLab与GitHub的不同 ◆ Github分布式在线代码托 ...

  10. eclipse git导入的项目 让修改后的文件带有黑色星标记样式

    操作方式:Window——>Preferences——>Team——>Git——>Label Decorations——>Icon Decorations 将 Dirty ...