1、lua学习之入门(一)----环境搭建
2、lua学习之入门(二)----基础语法1
3、lua学习之入门(二)----基础语法2
4、lua学习之入门(三)----函数
在LUA里函数是个十分重要的内容,因为我们实际开发的时候,用的最多的就是函数,用函数是封装各个实现,在Q群里曾经听一些大虾说过,写LUA必须要懂得闭包,常用系统函数,还有范型for写迭代器,最后就是编译和运行还有错误信息.其实这章,我就卡了一下壳,卡壳的地方在闭包,因为我没有完全理解闭包的作用,和闭包的好处,网上也没有明确的说明闭包的优劣,所以闭包的概念,我也只能以个人感觉去写,如果我说得不对,欢迎赐教.如果对闭包理解很深,欢迎来指教...你要偶拜你为师也行,达者为师啊,偶很好学的.
函数有两种用途:1.完成指定的任务,这种情况下函数作为调用语句使用;2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。
其实我们接触最早的,就是函数,还记得我们的第一个LUA吗?print();这就是一个函数.可以理解****()都可以当做是函数,其实大部分编程语言的函数都是以这个方式一共调用的.认识了什么是函数,那么我们就自己编写一个函数吧
function maxFun(a
,
b)
if
a
>
b then
return
a;
else
return
b;
end
end
--
我们用一个输出语句把我们的函数结果显示出来
,
证明我们写的函数没有问题
print
(maxFun(
4
,
3
));
上面这个函数
,
其实很简单就是比较两个数的大小
.
最后运行的结果我们得到结果是4
,
这里使用的是函数的第1种任务
,
判断两个数的大小
,
在LUA里函数是可以返回多个值的
,
这个点和其他编程语言有很大的区别
,
那就很容易造成错觉
,
多个返回值
,
那我如何获得各个返回值呢
?
看例子
function returnAnyValue()
return
1
,
2
,
3
,
4
;
end
a
,
b
,
c
,
d
=
returnAnyValue();
e
,
f
,
g
=
returnAnyValue();
h
,
i
,
j
,
k
,
l
=
returnAnyValue();
--
[[
print
(
"
a:
"
..
a
..
"
b:
"
..
b
..
"
c:
"
..
c
..
"
d:
"
..
d
..
"
e:
"
..
e
..
"
f:
"
..
f
..
"
g:
"
..
g
..
"
h:
"
..
h
..
"
i:
"
..
i
..
"
j:
"
..
j
..
"
k:
"
..
k
..
"
l:
"
..
l
..
"
!
"
);
]]
--
这样编译是出错的
,
提示告诉我们l为nil不能输出
.
--
所以我们把程序修改为
print
(
"
a:
"
..
a
..
"
b:
"
..
b
..
"
c:
"
..
c
..
"
d:
"
..
d
..
"
e:
"
..
e
..
"
f:
"
..
f
..
"
g:
"
..
g
..
"
h:
"
..
h
..
"
i:
"
..
i
..
"
j:
"
..
j
..
"
k:
"
..
k
..
"
!
"
);
结果如下
:
a
:
1
b
:
2
c
:
3
d
:
4
e
:
1
f
:
2
g
:
3
h
:
1
i
:
2
j
:
3
k
:
4
虽然我们不能输出L的值,但是我们根据错误提示可以知道l的值是nil的.
论述完返回值,那么我们要看参数数了,LUA支持可变参数的模式的使用的方法和C语言的差不多,不熟悉的可以先学C语言,毕竟我看到的LUA大多数都是嵌入C中的,所以C/C++至少你要会.
好了我们要进入我觉得比较难的点:闭包
在我接触的编程语言里,其实还没发现过闭包的概念,坦白的说一句,就是LUA我才接触闭包的.闭包从网上的资料来看,就是JAVASCRIPT里的匿名函数的使用(我接触新语言的时候,总喜欢用自己接触过的语言去进行对比,去学习.我觉得这种学习的方法还是比较有效果的,有兴趣的朋友也可以试试这个方法.),在我看了网上公开的闭包程序,最大的特点就是使用,外面的函数有自己的局部变量,内部的匿名函数使用了外部函数的局部变量.有点像面向对象思想里的意思,后来我在LUA的一个论坛看到一篇关于闭包的定义,如下:
当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。虽然这看起来很清楚,事实并非如此,词法定界加上第一类函数在编程语言里是一个功能强大的概念,很少语言提供这种支持。
技术上来讲,闭包指值而不是指函数,函数仅仅是闭包的一个原型声明
这个是我在网上找的一个关于闭包的例子,个人感觉水平有限.可能使用网上的例子更有说服力
这个例子主要说明的是在外部函数和内部函数之见参数的使用,函数中就可以直接用变量进行传值,这里需要说明一下的是table.sort(存放元素的数组,排序函数)具体的等后面我介绍常用库的时候说.只要知道是表排序就好.
函数就写出来的,但是我们需要更直观的看到这些资料
所以我在最下面加上了如下代码
print
(
"
---------
"
)
sortbygrade (names
,
grades);
for
v in pairs(names)
do
print
(names[v])
end
输出结果为
Mary
Peter
Paul我将grades = {Mary = 7, Paul = 8, Peter = 9}改了再看效果
Peter
Paul
Maryfunction newCounter()
local i = 0
return function() -- anonymous function
i = i + 1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
print(c1()) --> 3
结果代码里已经显示了,我就不说了,但是大家看到这个结果?你想到了什么?
对象?就是对象,看以下C#代码
public class CC
{
private int a;
public CC()
{
a=0;
}
public int newCounter()
{
this.a=this.a+1;
retrun this.a;
}
} 如果LUA代码里C1=newCounter();C2=newCounter()
print(c2())--->1
是不是跟我们声明一个对象十分的类似呢?所以我推断闭包在一定程度上实现了部分面向对象的功能,肯定有一定的差别的,我只是说类似..而且我看代码有点像C语言去实现面向对象的感觉...
闭包还可以实现类似JAVA里沙箱的功能,(来自网上,我并没有运行这段代码)
do
local oldOpen = io.open
io.open = function (filename, mode)
if access_OK(filename, mode) then
return oldOpen(filename, mode)
else
return nil, "access denied"
end
end
end
*正确的尾调用
这个迷宫游戏是典型的状态机,每个当前的房间是一个状态。我们可以对每个房间写一个函数实现这个迷宫游戏,我们使用尾调用从一个房间移动到另外一个房间。一个四个房间的迷宫代码如下:
function room1 ()
local move = io.read()
if move == "south" then
return room3()
elseif move == "east" then
return room2()
else
print("invalid move")
return room1() -- stay in the same room
end
end
function room2 ()
local move = io.read()
if move == "south" then
return room4()
elseif move == "west" then
return room1()
else
print("invalid move")
return room2()
end
end
function room3 ()
local move = io.read()
if move == "north" then
return room1()
elseif move == "east" then
return room4()
else
print("invalid move")
return room3()
end
end
function room4 ()
print("congratilations!")
end
我们可以调用room1()开始这个游戏。
如果没有正确的尾调用,每次移动都要创建一个栈,多次移动后可能导致栈溢出。但正确的尾调用可以无限制的尾调用,因为每次尾调用只是一个goto到另外一个函数并不是传统的函数调用
(以上代码来源网上)
正确尾调用论述的意义在于..栈溢出的问题,不正确的尾调用是存在栈溢出问题的.
这篇写的我自己都不是很满意...因为这个东西..需要点时间消化...等我消化了再来整理一下,就好象开头,我也是一个LUA新手,我只能把我认识的弄出来,而且正确上..也非绝对..其实我的目的只是传播我的学习的思想.
明鏡臺
posted on 2009-05-14 13:14
^乔乔^ 阅读(2071)
评论(0) 编辑 收藏 引用 所属分类:
Lua学习笔记