这块主要记录Lua语句的写法
Lua中除了基本的赋值、控制结构、过程调用语句外,还有一些特殊用法如多重赋值(multiple assignment)和局部变量声明
赋值语句
多重赋值语句用法:
> a,b=10,20
> print(a)
10
> print(b)
20
>
在多重赋值语句中,Lua会先将等号右边所有元素都求值完然后依次对左边赋值,并且右边多出来的将会被丢弃。若右边值少于左边变量,则左边多余的变量会被赋nil
如下语句是将x,y值交换:
x , y = y , x
多重赋值的意义:
- 用于变量交换
- 接受函数多个返回值时,如a,b=fun(),fun()将返回两个值,a接收第一个,b接收第二个
局部变量和块(block)
局部变量的定义 local i=1,作用于一个语句块即一个控制结构内或一个函数内。需要注意的是,交互模式即命令行下本身每一行就是一个语句块,上一行定义的local变量可能到下一行就失效了。可通过do end来指定变量的作用域,如下do end包起来的部分就是a2的作用域.
> do
>> local a2=123
>>
>> print(a2)
>> end
123
>
Lua的控制结构
关键字 | 作用 |
---|---|
if | 以end结尾 |
while, repeat, for | 用于循环,while和for以end结尾,repeat以until作为结尾 |
if语句学习:
--if语句
print("\n\n if语句测试: input a please:")
str=io.read()
a=tonumber(str)
if( a == nil) then
print(str.." is not number")
elseif(a<0) then
print("input less than 0")
elseif (a==0) then
print("input is 0")
else
print("input more than 0")
end
while语句:
--while study
a={12,31221,"fdafdf","fdf","43424",true,false}
local i=1
while(a[i]) do
print( a[i])
i=i+1
end
repeat语句用法:
--但打印输入的第一行不为空的内容
print("输入字符串并换行,#为终止")
repeat
line = io.read()
until line == "#"
print(line)
for语句demo:
--[[for循环语句,
数字型的结构
for var exp1,exp2,exp3 do
<执行体>
end
其中exp1为起点,exp2为变化终点,exp3为步长
--需要注意:
1.是exp123是在开始前一次性求值的。
2.var 限定了有效周期只在if语句内,
因此如果end之后还想拿var的值,只能在循环中把var存到别的变量中去!
--]]
for i = 1, 100, 6 do
print(i)
end
--[[
泛型的for(generic for),通过迭代器来遍历所有值,
Lua标准库提供的迭代器:
1.迭代文件中每行的io.lines
2.迭代table元素的pairs
3.迭代数组元素的ipairs
4.迭代字符串中单词的 string.getmatch
--]]
print("\n\n\n泛型的for测试:")
a={"fdfsd","dsd",1232,true}
for i,v in ipairs(a) do
print(v)
end
break和 return 语句
--[[
for 语句的一个用法,逆向table.
--]]
days={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}
revdays={}
for k,v in pairs(days) do
revdays[v]=k
end
print("revdays=")
print(revdays)
print("days['Sunday']=",days["Sunday"])
print("revdays['Sunday']=",revdays["Sunday"])
break和return语句:
书中说:
break and return 必须是一个块的最后一条语句,或是end,else,until前的一条语句?
并且举例直接写一个空函数如下:
function foo()
return
说是语法错误,空return或break需要用do end 包起来。
但是我在自己的解释器尝试了下,直接写空语句是正常的。
这部分主要记录Lua的函数语句相关
普通函数
在Lua中,语句的特点:
- 函数语句提供多种写法
以print()函数为例:
-- print() fucntion
a=123
print(a) -- normal print
print "ffdfdfd" -- when print one string or table
print [[fasdfasffdf
fdghfdgf
ghfhghg]] --when print multiline string
- Lua中函数实参的个数可以跟形参不同,Lua会根据实际情况决定补默认参数 还是丢弃多余参数
传参demo:
-- about function parameters
function testFun( a, b) return a or b end
print( testFun(12,32))
print( testFun(12,"lisi",3232))
print( testFun( ))
print( testFun( "sdf"))
- Lua函数可以有多个返回值的特性,结合多重赋值语句来用。
如下demo函数有两个返回值并使用:
--function multiple results
s,e = string.find("hello lua user", "us")
print("find res=",s,e)
并且,当多重赋值语句的右边多个参数中包含参数调用的时候:
如果右边的函数调用不是再最后一个位置,则赋值时,只会取用函数的第一个返回值给左边赋值。
如下的执行结果,z,m都为nil了
> x,y,z,m=string.find("hello lua user", "us"),"zhangaaa"
> print(x,y,z,m)
11 zhangaaa nil nil
==但是, 如果函数作为右边最后一个参数,会将函数所有返回值依次赋值给左边,==
除非左边的变量不够导致结果丢弃。比如语句,则x,y,z都会有值,m会被填为nil
> x,y,z,m="zhang",string.find("hello lua user", "us")
> print(x,y,z,m)
'zhang'
11
12
>
但是如果想要避免Lua取多个函数返回值给左赋值呢?可以在调函数的时候加括号,限定它只返回一个结果:
> x,y,z,m="zhang", (string.find("hello lua user", "us"))
> print(x,y,z,m)
'zhang'
11
>
此外,圆括号除了在赋值情境中,普通函数return中也具有截取第一个值的效果,如下demo:
-- () special use
function getname(a) return a,"a girl" end
function getname_2(a)
return getname(a) --return a all results
end
function getname_3(a)
return (getname(a)) --return a first results
end
运行结果,会发现print(getname_3(“aabb”)) 只有一个返回值了。
> print(getname(12))
12
'a girl'
> print(getname_2("aa"))
'aa'
'a girl'
> print(getname_3("aabb"))
'aabb'
>
特殊函数unpack函数,可实现变长参数的传递。unpack函数会接受一个数组。
--系统函数 unpack,实现动态的传递参数,实现任意函数的调用
--like f(unpack(a))
f= string.find
a={"hello world","worl"}
> print( f(unpack(a)))
7
10
>
变长参数(variable number of arguments)
如下实现一个边长参数的求和:
--定义一个边长的函数?
function add(...)
local s=0;
for i, v in ipairs{...}do
s = s + v
end
return s
end
> print(add(1,2,3,4,45,5,5))
65
>
小demo,如下格式化显示函数,长的特别像C语言的打印函数,注io.write()函数的打印结果是不带换行的
--格式化文本 string.format和输出文本 io.write函数
function fwrite(fmt,...)
return io.write(string.format(fmt,...))
end
> fwrite("%d%s",23,"zhang san")
23zhang san>
具名实参用法(named arguments),即像C#中的传参时通过paramName:value的形式指定传那个参数的值。
但是在Lua中是默认不支持具名实参的,即便是在系统函数的使用中,因此,想要实现具名实参的效果 只能自己“包装一下”,或者在自定义函数中去实现这个效果。
以系统函数os.rename()文件重命名为例,调用方法只能是:
os.rename("e:/project/mystudy/luastudynew/test_3.lua","e:/project/mystudy/luastudynew/test_4.lua")
但是可以添加一个自定义函数去实现具名实参的效果,基本思想是将函数参数改造为table,talbe就有key value的属性了。但是会发现,调用方法也会有不同,原先是圆括号()的格式,改造后变成了rename{}的格式,
function rename(arg)
return os.rename(arg.old,arg.new)
end
--调用
> rename{old="e:/project/mystudy/luastudynew/test_3.lua",new="e:/project/mystudy/luastudynew/test_4.lua"}
尽管如此看起来比较别扭,但在遇到超长系统函数时。改造一下还是值得的
深入函数
既然单拆出一个章节,应该是概念有别于普通函数,在Lua中,函数属于“第一类值”(First-Class Value),即跟数字、字符串等的操作方法都相同。函数的调用也相当于一个表达式。
如下这两个函数的声明方法,第二个方法更直接解释了,函数的声明就相当于定义了一个返回类型为函数的表达式啊
> function foo(x) return 2*x end
> print(foo(3))
6
> foo=function(x) return 2*x end
> print(foo(3))
6
>
闭合函数(closure)的概念
词法域的概念:
若将一个函数写在另一个函数内,则这个位于函数内部的函数便可以访问外部函数中的局部变量。
小贴士:由于在Lua中函数可以保存到变量中,这个特性可以实现函数的重定义,甚至是重定系统函数。
用途:可以限定使用 被重新实现的函数。
如下demo重定义了系统函数math.sin(),在装载该文件前后,执行math.sin的效果是不同的,默认sin()的参数是作为一个弧度的,但重定义之后的函数sin()参数会作为一个角度来使用。
--实现系统函数 math.sin()的重定义,以后调用math.sin()都相当于调用这个函数了。
do
local oldSin = math.sin; --将老的系统函数保存在了局部变量中。
local k = math.pi/180
math.sin=function(x)
return oldSin(x*k)
end
end
> print(math.sin(12))
-0.53657291800043
> dofile "e:/project/mystudy/luastudynew/function_demo.lua"
> print(math.sin(12))
0.20791169081776