Lua脚本语言学习中级篇

函数进阶

1.参数的简化:函数若只有一个参数,且此参数是一个字符串或者table构造式,则(实参)圆括号可以省略。建议不使用简化

例如:

function SetName(str)

print(str)

end

--SetName("test") 这是未简化的

SetName "test" 这是简化后的

--table类型简化

function Set(namearray)

for k,v in pairs(namearray) do

print(v)

end

end

--array={"1","2","3"}

--Set(array)  这是未简化的

Set  {"t","e","s"}  这是简化的

2.可变参数:又称为变长参数,使用符号...表示多个参数,主要应用于形参中,这里的关键字功能类似C#中的para关键字

例如

function MultiParaVal(...)

for k,v in pairs({...}) do  --使用{...}访问变长参数

print(v)

end

end

MultiParaVal("asd","qwe","zxc")

注意:A.在lua5.0以上版本通过局部table变量“arg”可以接收所有变长参数。arg是lua的内置函数,本质是把可变参数封装为一个表,#arg可表示参数个数;

  访问变长参数时,使用{...}或者arg访问

例如

function MultiParaVal(...)

--for k,v in pairs({...}) do

-- print(v)

--end

for k,v in pairs(arg) do   --arg可表示{...}

print(v)

end

end

MultiParaVal("asd","qwe","zxc")

注意:B.如果变长参数中包含nil,则必须使用“select”来访问变长参数。调用select时必须传入一个固定的实参select(选择开关)和一系列变长参数。

格式:1.select(index,...)返回从index下标开始,一直到变长参数列表结尾的所有元素

2.select(‘#’,...)返回变长参数列表长度

例如

function MultiParaVal(...)

print(select('#',...))

print(select(1,...))

end

MultiParaVal("asd","qwe","zxc",nil,"jkl")

结果为 5   asd qwe zxc nil jkl

3.标准函数库:lua的标准函数库也是lua 的内置函数,主要分三大类:

数学函数

print(math.abs(-88)) --求绝对值

print(math.max(12,55,62,32)) --求最大值

print(math.min(12,55,62,32)) --求最小值

print(math.sin(0)) --求sin

print(math.cos(0)) --求cos

print(math.sqrt(36)) --求平方根

print(math.random(1,10)) --求随机数,有问题

print(math.floor(18.88)) --取整

......

字符串函数

print(string.lower("weTySD")) --全部小写

print(string.upper("weTySD")) --全部大写

--还有很多

操作系统库

print(os.date()) --得到日期

print(os.time()) --得到时间,得到的不是常规的时间

应用案列:使用操作系统的时间系统函数,配合随机函数,开发准确的随机数函数

function GetRandom(min,max)

--得到时间字符串

local strtime=tostring(os.time())

print(strtime)

--得到一个反转字符串

local strRev=string.reverse(strtime)

print(strRev)

--得到前6位

local strRandomTime=string.sub(strRev,1,6)

print(strRandomTime)

--设置时间种子

math.randomseed(strRandomTime)

print(math.random(min,max))

end

GetRandom(50,100)

非真随机,结果明显几张在50~70间

4.函数尾调用:lua中可以再一个函数中,使用return返回另一个函数,这种预防成为“尾调用”。形式如:function f(x)  return g(x) end

在递归算法中,因为调用g(x)后,f(x)中不再执行任何代码,所以不需要保留f(x)的调用桟信息;Lua做了这样的优化,称为"尾调用消除",g(x)返回后,控制点直接返回到调用f(x)的地方。尾调用不占用“堆栈”空间,所以不会出现“栈溢出”,可以起到优化存储空间的作用,例如

function f(n)

if n <= 0 then

return 0

end

a = f(n-1)

return n * a --非尾调用,当递归次数过多则报错"栈溢出"

end

--print(f(50000))

function f1(n)

if n <= 0 then

return 0

end

return f1(n-1) --尾调用,递归次数多也不会栈溢出

end

print(f1(50000))

尾调用时可以加()包住返回的方法,其作用是只返回方法的一个结果,形式为return(g())

例如

function func()

print("func")

--return fund() --此方法返回方法的所有结果:func  fund  100  200

return (fund()) --此方式只返回方法的一个结果: func  fund  100

end

function fund()

print("fund")

return 100,200

end

print(func())

5.函数的本质:lua函数本质是匿名的,即没有名称,讨论一个函数本质是讨论一个持有此函数的变量。

函数与普通类型的数值权利相同。

  1. 可以用一个变量或table指向函数,也可以作为实参传递给其他函数,还可以作为其他函数的返回值
  2. 本质上函数就是一条语句,可以将其存储在全局变量中,也可以存储在局部变量中

例如

function fun(num)

return num+1

end

array={}

array[1]=function(num) --方法1

return num*2

end

array[2]=function(num)

return num

end

array[3]=fun --方法2

for k,v in pairs(array) do

print(v(5))

end

print(array[1](10))

6.闭包:一个函数中嵌套子函数,子函数可以使用父函数中的局部变量,这种行为就叫做闭包,可以简略归纳为:闭包=函数+引用环境(非局部变量)

闭包的特点:闭包中的内嵌函数可以访问外部函数已经创建的所有局部变量,这些变量称为内嵌函数的“upValue”

闭包与一般函数的区别:闭包只是在形式和表现上像函数,但是实际上不是函数,函数只有一个实例,定义以后逻辑就确定了,不会执行时发生变化

“词法域”概念,若将一个函数写在另一个函数内,那么这个位于内部的函数便可以访问外部函数的局部变量,这项特征叫做“词法域”(就是闭包),外部函数的局部变量在匿名函数内既不是全局变量也不是局部变量,称其为“非全局变量”

   闭包的典型应用:迭代器的实现可以记住闭包函数实现,闭合函数能保持每次调用间的一些状态

例1:无参数闭包

function Fun()

local i=0 --i变量成为内嵌函数的"upValue"

--这里的i既不是全局变量,也不是局部变量

--这里i称为“非局部变量”

print("--A--i=",i)

return function() --内部嵌入的匿名函数

print("--B--i=",i)

i=i+1

print("--c--i=",i)

return i

end

end

v=Fun()

print(v())

print(v())

print(v())

结果为

--A--i= 0

--B--i= 0

--c--i= 1

1

--B--i= 1

--c--i= 2

2

--B--i= 2

--c--i= 3

3

例2:带参数闭包

function Fun(i) --参数i是内嵌函数的"upValue"

print("a/i=",i)

return function()

print("b/i=",i)

i=i+1

print("c/i=",i)

return i

end

end

f=Fun(10) --此时已经执行Fun函数,打印了a/i= 10,然后返回的是一个 函数,将函数赋值给了f,f也就是一个函数了

print(f()) --这里f()执行了函数,打印了b/i= 10,然后i加了1,又 打印了c/i= 11,然后返回了i,由最后的print打印了i的值

print(f()) --重复上面的过程,注意此时i已经加了1

print(f())

结果为

a/i= 10 --执行f=Fun(10)时打印

b/i= 10

c/i= 11 --执行print(f())时打印,下面的同理

11

b/i= 11

c/i= 12

12

b/i= 12

c/i= 13

13

例3:具备多个内嵌函数的闭包

function Fun()

local num=10 --两个内嵌函数对upValue进行共享处理

function In1() --内嵌函数1,负责打印

print(num)

end

function In2() --内嵌函数2,负责计算

num=num+10

end

return In1,In2

end

v1,v2=Fun()

v1()

v2()

v1()

结果为10   20

例4:带参数的内嵌函数

function Fun(num)

print("a/num=",num)

return function(value)

print("b/num=",num)

num=num*value

print("c/num=",num)

return num

end

end

fun=Fun(4)

print(fun(2))

print(fun(2))

print(fun(2))

结果为

a/num= 4

b/num= 4

c/num= 8

8

b/num= 8

c/num= 16

16

b/num= 16

c/num= 32

32

例5:闭包具备多个实例

function Fun(num)

print("a/num=",num)

return function(value)

print("b/num=",num)

num=num*value

print("c/num=",num)

return num

end

end

fun=Fun(4) --执行到这里时,num初始化为4,打印a/num=4

print(fun(2)) --此时打印b/num=4,num赋值为4*2,打印c/num=8,然后返 回num,打印8

print(fun(2)) --步骤同上

Fun1=Fun(5) --执行到这时num被重新初始化为5,接下来步骤同上

print(fun1(2))

print(fun1(2))

结果为

a/num= 4

b/num= 4

c/num= 8

8

b/num= 8

c/num= 16

16

a/num= 5

b/num= 5

c/num= 10

10

b/num= 10

c/num= 20

20

例6:使用闭包实现自定义迭代器

function Fun(array)

local i=0

return function()

i=i+1

return array[i]

end

end

ar={1,2,5,8,9,10}

f=Fun(ar)

--方式1使用while

--while(true) do

-- local v=f()

-- if(v==nil) then

-- break

-- end

-- print(v)

--end

--方式2使用for

for m in Fun(ar) do

print(m)

End

结果为:1 2 5 8 9 10

7.加载其他lua脚本

使用require(“路径”)这个方法可以运行指定lua脚本,其中路径为本文件的相对路径,若需要运行的文件与本文件同目录,则直接填入需要运行的文件名称不加”.lua”后缀,例如require("Test")以及require("Test1/Test")(不同目录)

注意点:

文件名不能带有特殊字符例如”.”等,“/”除外,否则会导致加载错误

文件拓展名.lua不需要编写,因为会自动添加

同一个文件无法同时被加载多次,因为存在一个表会记录已经加载得到文件,这个表就是package.loaded[“文件相对路径”],

例如print(package.loaded["Test1/Test"])结果为True,当每次加载文件时,都会检查package.loaded里面的内容,若为True则不加载否则加载,这样可以防止重复加载。其中,package.loaded中存储的是程序员所写的文件的路径,若同一个文件加载所写的路径不同可以重复加载,例如require("Test1/Test")和require("./Test1/Test"),加载同一个文件,但是路径写法不同,可以重复加载。若想重复加载一个文件,则需要在加载前清除这个状态,清除这个状态的方法为设置其为nil或false,

例如package.loaded["Test1/Test"] = nil 或package.loaded["Test1/Test"] = false

8.获取其他文件的局部变量

例如有一个lua2.lua脚本,存在一个局部变量config,

local config = {}

config.appName = "mlg"

此时要想其他文件拿到这个config局部变量需要lua2中返回这个变量

local config = {}

config.appName = "mlg"

return config

这时使用local fig = require(“lua2”),可以拿到lua2中的局部变量,就能使用了

9.元表

local t1 = {1,2,3}

local t2 = {2,3,4}

--直接打印表,结果为表的内存地址

--print(t1)

--我们希望打印table时,打印为表的内容,如{1,2,3}

--打印时将表一字符串输出

--为了实现这种方法,lua提供了这种语法特性,元表拓展(metatable拓展)

local meta = { --拥有拓展t1的元表,只要在元素中实现一些特殊的函数,则

--t1就能实现一些特殊的功能,比如让t1作为字符串使用

__tostring = function(t) --元方法,当被拓展表被以string方式调用时调用

local format = "{";

for k,v in pairs(t) do

format = format..v..",";

end

format = format.."}";

return format

end

}

setmetatable(

t1, --需要进行元表拓展的数据表

meta

)

setmetatable(

t2, --需要进行元表拓展的数据表

meta

)

print(t1)

print(t2)

其中__tostring是固定的元方法,还有__add(相当于实现加法操作,至于如何加自定义)等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值