三:编程技巧
1、 闭包:
简单来说,一个闭包就是一个函数外加能够使该函数正确地访问非局部变量所需的其他机制。
介绍一个闭包应用的场景:当重新定义一个函数时,我们需要在新的实现中调用原来的那个函数。例如,假如要重新定义函数sin一使其参数以角度为单位而不是以弧度为单位。那么这个新函数可以先对参数进行转换,再调用原来的sin函数进行真正的计算。
do
local oldSin = math.sin
local k = math.pi/180
math.sin = function(x)
return oldSin(k*x)
end
end
上述代码使用了do代码来限制局部变量oldSin地作用范围。我们可以使用同样的技巧来创建安全地运行时环境,即所谓的沙盒。
(1):在Lua语言中,函数是严格遵守词法定界的第一类值。“第一类值“意味着Lua语言中的函数与其他常见类型的值(例如数值和字符串)具有同等权限。”词法定界“意味着Lua语言中的函数可以访问包含其自身的外部函数中的变量。
(2):高阶函数:举例说明,
table.sort(table1,function (a,b) return (a.name>b.name) end)
该以另一个函数作为参数的函数被称为高级函数,其实现基于匿名函数的机制:函数定义实际上是创建类型为“function“的值并把它赋值给一个变量的语句,即函数是没有名字的,即匿名(anonymous)。
(3):非全局函数:函数不仅可以被存储在全局变量中,还可以被存储在表字段和局部变量中。其中,存储在表字段中是Lua实现面向对象的编程的关键要素。举例说明,
local fact
fact=function (n)
if n==0 then return 1
else return n*fact(n-1)
end
end
该程序段是一个局部的嵌套函数。
(4):词法定界:当编写一个被其他函数B包含的函数A时,被包含的函数A可以访问包含其地函数B的所有局部变量,我们将这种特性称为词法定界。
(5):函数式编程:以开发一个表示几何区域的简单系统为例。
定义一个根据指定的圆心和半径创建的圆盘:
function disk (cx,cy,r)
return function (x,y)
return (x-cx)^2 + (y-cy)^2 <= r^2
end
end
定义一个指定边界的轴对称矩阵:
function rect (left,right,bottom,up)
return function (x,y)
return left <= x and x <=right and
bottom <=y and y<=up
end
end
2、 模式匹配:
(1) 模式:Lua语言中的模式使用百分号%作为转义符。
下列列出了所有预置的字符分类和其含义:
. | 任意字符 |
%a | 字母 |
%c | 控制字符 |
%d | 数字 |
%g | 除空格外的可打印字符 |
%l | 小写字符 |
%p | 标点符号 |
%s | 空白字符 |
%u | 大写字符 |
%w | 字母和数字 |
还可以通过描述模式中重复和可选部分的修饰符(modifier)来让模式更加有用。
+ | 重复一次或多次 |
* | 重复零次或多次 |
- | 重复零次或多次(最小匹配) |
? | 可选(出现零次或一次) |
(2)字符串标准库提供了基于模式的4个函数,分别是:string.find,string.match,string.gsub,string.gmatch
string.find:参照如下代码段
s = “hello achevery,how are you”
i.j=string.find(s,”hello”)
print(i,j) --》 1 5
string.match:参照如下代码段
data=”Today is 2021/9/27”
d=string.match(data,”%d+/%d+/%d+”)
print(d) --》 2021/9/27
其中,“%d+“表示一个非空的数字序列,类似的,模式”%a+“表示一个非空的字母序列,”%s*“表示一个可能为空的空白序列。
string.match具有捕获模式,即将所有捕获到的值作为单独的结果返回,可以通过把模式中需要捕获的部分放到一对圆括号内来指定捕获。如:
pair = “ name =achevery”
key,value=string.match(pair,”(%a+)%s*=%s*(%a+)”)
print(key, value) --》 name Anna
string.gsub:该函数有三个必选参数,目标字符串、模式和替换字符串,其基本用法是将目标字符串中所有出现模式的地方替换成替换字符串。如:
s=string.gsub(“achevery is cute”, “cute”, “great”)
print(s) --》 achevery is cute
函数string.gsub的第三个参数不仅可以是字符串,还可以是一个函数或表。
当第三个参数是一个函数时,函数string.gsub会在每次找到匹配时调用该函数,参数是捕获到的内容而返回值则被作为替换字符串。当第三个参数是一个表时,函数会把第一个捕获到的内容作为键,然后将表中对应该键的值作为替换字符串。
举例,格式转换器:将LATEX风格的命令(\example{text})转换成XML风格的(<example>text</example>)。
function latextoxml (s)
s=string.gsub(s,\\(%a+)(%b{}),function (tag,body)
body=string.sub(body,2,-2) --移除括号
body=toxml(body) --嵌套
return string.format(“<%s>%s<%s>”,tag,body,tag)
return s
end
)
string.gmatch:该函数可以遍历作为参数的字符串中所有出现的指定模式,其常常这样使用,如例:
for w in string.gmatch(s,”%a+”) do
……
end