Lua,让人惊叹的艺术!

本文深入探讨了Lua语言的函数用法,包括匿名函数、局部和全局函数,以及如何通过函数创建闭包。进一步,文章介绍了Lua中的对象和类的概念,展示了如何实现函数作为构造器来创建对象,以及对象的方法调用。同时,文章还讨论了元表和元方法在创建自定义操作符和类继承中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lua 对于国人来说可能还比较陌生,然而随着它在电子娱乐、网络娱乐界得到大量的应用,许多人也开始关注起它来。

Lua 虽然是一门脚本语言,但麻雀虽小,五脏却俱全。Lua 主要是面向过程的语言,与大多数脚本语言无异;但 Lua 围绕“栈”的语言构造,强大的表格基本类型,不仅让它身手敏捷(所有优秀脚本语言中速度最快的),而且拥有了百变金身(语法优美,灵活多变),如果说一些语言标榜的诸多特性,例如面向对象,对于 Lua 来说,居然只要用点“语法糖”就能搞定,你是不是觉得有点夸张了?

夸张的事情在 Lua 中可不止这一件,关键的关键是,Lua 实现它们都不费吹灰之力,也不用艰深的语法,这才是所有夸张中最夸张的。那么,如果你也开始觉察到 Lua 的不普通的话,就请随我一同走进 Lua 的世界。

新手提示:可以下载最新的 LuaEdit 这个程序,来编辑和运行 Lua 脚本。你可以很容易的从网上找到并下载它,3.0或以上版本就足够运行下面的示例了。打开 LuaEdit,File-New Unit,输入或粘贴代码,按“播放”键即可。

Lua 之简

Lua 给我们的东西,或者说需要我们记住的东西,只有变量、关键字和基本语法。而关键字和语法又与常见语言几乎一样,像if...then...elseif...else...end, while...do, for...in, function, repeat(循环次数控制), return; 像 +、-、*、/、^ 之类的标准数学符号 -- 这些对于编程有点基础的人来说,都几乎免学习。所谓“变量”的东西除了能装单个的数、字符串、表(table)、函数(function)以外,就是所谓的自定义数据(userdata)了,这个 userdata 理论上可以放任何东西,但如果 Lua 没有一个宿主的话,它似乎也不会被用到,所以无视它。

总之,Lua 给我们的一切,用一页纸几乎可以全部写出来(参见 Lua 5.1 白皮书索引前一页),而标准库则更是简到了“精致”的地步(可以参见本 Blog 的 Lua 基础篇转载)。

超出这一页,那么请发挥自己的想象力吧!


函数语法糖

在 Lua 编程者看来,Lua 的函数就是一种特殊的变量,用 function 声明它,用 () 紧跟在变量名后来使用它,像这样:

  1. f = function(x,y)
  2.        return x + y
  3.     end
  4. print(f(1,1))-- 注释:print 全局函数用于在控制台打印文字,此处输出 “2”
当然,对于一个习惯了C,Java等语言的编程者来说,会感觉上述语法有些怪异,有点北方人碰上个四川人讲话的感觉 -- 明白但拗口。Lua 不希望别人叫它拗口的语言(尽管 Lua 这个词是个西班牙语词,意思为月亮),于是为众多不同口味的人准备了语法糖,来个 VB/Delphi 款式怎么样?
  1. function f(x,y)
  2.   return x + y
  3. end
  4. print(f(1,1)) -- 输出“2”
嵌套函数

既然 Lua 的函数本质上就是一个普通变量,那么我们想在哪里用它都行,即使是在一个函数里面来使用函数!

  1. function f(x,y)
  2.   function f1(x)
  3.     return x = x + 1
  4.   end
  5.   return f1(x)+y
  6. end
  7. print(1,1) -- 显示"3"
这被称为“内嵌函数”,并且也不是 Lua 的专利,Javascript 也具备这种能力。

多返回值函数和无限形参

如果说这有些让你不太舒适,那么函数的如下功能,应当会让你略感顺心如意,请看多返回值函数:

  1. function f(x)
  2.   return x, x+1, x+2
  3. end
  4. y,y1,y2=f(1)
  5. print(y,y1,y2) -- 打印“1 2 3”
要接收3个参数啊,麻烦,我只想接收一个:那么不接收就行了:

  1. function f(x)
  2.   return x, x+1, x+2
  3. end
  4. y = f(1)
  5. print(y) -- “1”
不不,我只要接收第2个参数:。。。那你把第一个参数一“扛”了之:

  1. function f(x)
  2.   return x, x+1, x+2
  3. end
  4. _, y1 = f(1)
  5. print(y1) -- “2”

有难以计数的参数准备传入到函数?传入参数少了一项??忘记了传入参数???很好,Lua 其实就是为那些不喜欢事先精确设计每一件事情的人而设计的,一切尽在“ ...”中:

  1. function f(...)
  2.   for _, x in ipairs(arg) do
  3.     print(x)
  4.   end
  5. end
  6. f(4,5,6)
  7. --打印出:
  8. --4
  9. --5
  10. --6
Lua 怎么做到的?答案得归功于 Lua 栈式的内部存储结构和典型容器:表。

放在函数里的 OOP

下面,我们来挑战下函数的极限:想用函数来模拟面向对象编程(OOP) 吗? 这个 Lua 函数实现的“狼吃兔子”游戏:

  1. function CreateAnimal(species,food,hungry,speed,living)  -- 初始化动物类函数,参数依次为 种类、食物、饥饿度、速度、存活标记 
  2.   local function getSpecies() return species end
  3.   local function getHungry() return hungry end
  4.   local function getSpeed() return speed end
  5.   local function getFood() return food end
  6.   local function getLiving() return living end
  7.   local function setLiving(bLive) living = bLive end -- 设置为 false,表示该动物已死亡 
  8.   local function eat(otherAnimal) -- 如果觅食主体的食物就是客体的种类,并且主体饥饿度大于0,并且主体的奔跑速度大于客体,则吃下客体,客体死亡,主体饥饿度下降1 
  9.     if(food == otherAnimal.getSpecies() and hungry > 0 and speed > otherAnimal.getSpeed()) then
  10.       hungry = hungry - 1
  11.       otherAnimal.setLiving(false)
  12.     end
  13.   end    
  14.   return {getSpecies = getSpecies,getLiving = getLiving,setLiving = setLiving,getSpeed = getSpeed,getFood = getFood,getHungry = getHungry,eat = eat}  
  15. end
  16. rabbit = CreateAnimal("rabbit","grass",1,10,true) --新建一个动物:兔子 
  17. wolf = CreateAnimal("wolf","rabbit",2,20,true) --新建一个动物:狼 
  18. print(rabbit.getLiving(),wolf.getHungry()) -- true2 
  19. wolf.eat(rabbit) --狼吃兔子 
  20. print(rabbit.getLiving(),wolf.getHungry()) -- false1 



function 不经意间变成了几乎与 class 相媲美的存在,要不是因为必须为每一个想输出的属性都得做一个 Get,Set这样的函数麻烦,function 还真成了香饽饽了。

要想解释清楚上述代码的工作原理,着实不容易,得用到“闭包”之类比较深奥的概念。不过,如果只是简单的假设函数传入过来的形参也就是一些普通的本地变量的话(local variables),因为使用这些变量的函数还存在着(被 rabbit、wolf 所引用),所以这些变量也未被垃圾回收,从而发挥了私有数据(从某种意义上来说还是这几个函数的共享数据)的作用。

匿名函数

“闭包”也有实际的用途,下面这个函数返回了一个匿名函数,作为计数器使用。

  1. function createCounter()
  2.   local counter = 0
  3.   return function()
  4.             counter = counter + 1
  5.             return counter
  6.          end
  7. end
  8. f = createCounter()
  9. print(f())
  10. print(f())
  11. -- 输出
  12. -- 1
  13. -- 2


table-类的原型!

有人说 table (表类型,Lua 里,“ v = {}”就建立了一张空表)就相当于一个数组,一个C的结构体变量,一个 Python 的 List+Dictionary,或者一个Javascript 的 Object。其实都是,也都不是。数组不能有负数作为下标;结构体一旦生成,就不能往里面添加数据或函数成员;Object可不是默认就支持 [] 的寻址操作的。下面就是一个比较夸张的 table 的例子:

  1. Mary = {name='Mary',
  2.      title='Miss.',
  3.      age=28,
  4.      friends={ 'Mike','John'},
  5.      getAge=function(self,asker) 
  6.            r = table.foreach(self.friends,function(i,v) 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值