Lua基础(二)

转自http://blog.youkuaiyun.com/lyh916/article/details/49755339,请点击链接查看原文,尊重楼主版权。

----------------------------------------------------------------------------------------------------------------------------------------------------------------

五.函数


在lua中,若一个函数只有一个参数,并且此参数是一个字符串或table构造式,那么圆括号便可不写。

print "hello world"     --等同于print("hello world")  
print {10,20}           --等同于print({10,20})  


多重返回值:lua允许函数返回多个结果。根据情况,函数返回值的个数也不同
a.若将函数作为表达式的一部分来调用时,只保留函数的第一个返回值
b.当一个函数调用是一系列表达式中的最后一个元素(或仅有一个元素)时,才能获得函数的所有返回值

这里的"一系列表达式"在lua中表现为4种情况:多重赋值、函数调用时传入的实参列表、table的构造式和return语句

function foo0() end  
function foo1() return "a" end  
function foo2() return "a","b" end  
  
---------------------------a----------------------  
x,y = foo2(),20  
print(x,y)                   --a 20  
print(foo2().."x")           --ax  
t = {foo2(),4}               --t[1]="a",t[2]=4  
  
---------------------------b----------------------  
--1.多重赋值  
x,y,z,w = 1,foo2()  
print(x,y,z,w)                 --1 a b nil  
  
  
--2.函数调用时传入的实参列表  
print(foo2())                --a b  
  
  
--3.table的构造式  
t = {foo2()}                 --t = {"a","b"}  
  
  
--4.return语句  
function foo()  
    return foo2()  
end  
print(foo())                 --a b  
  
  
--可以将函数放入一对圆括号中,从而迫使它只返回一个结果  
print((foo2()))              --a  
--函数unpack,接受一个数组作为参数,并从下标1开始  
--返回该数组的所有元素  
  
print(unpack({10,20,30}))    --10 20 30  
变长参数:

--参数表中的...表示该函数可接受不同数量的实参  
function add(...)  
local sum = 0  
  
for i,v in ipairs({...}) do  
sum = sum + v  
end  
  
return sum  
end  
  
print(add(1,2,3,4))            --10  
print(add(1,2,3))               --6 
前面提到,函数是可以存储在变量中的。函数与其他所有值都是匿名的,即它们都没有名称。当讨论一个函数名时,实际上是在讨论一个持有某函数的变量。

a = {p = print}  
a.p("hello woeld")     --hello woeld  
print = math.sin  
a.p(print(3.14159))    --约等于0  
sin = a.p  
sin(10,20)             --10 20 
所以对于:
function foo(x) return 2*x end
其实就是等于:

foo = function (x) return 2*x end


--匿名函数的使用

--table库提供了一个函数table.sort,它接受一个table并对其排序  
--它的第二个参数是一个匿名函数,该函数接受两个元素,并返回  
--在有序情况下第一个元素是否应该排在第二个元素之前  
  
a = {  
{name = "aa",hp = "50"},  
{name = "zz",hp = "30"},  
{name = "cc",hp = "70"},  
}  
  
table.sort(a,function(a,b) return (a.name > b.name) end)  
for i,v in ipairs(a) do  
    print(v.name)        --zz cc aa  
end  
若将一个函数写在另一个函数之内,那么这个位于内部的函数便可以访问外部函数中的局部变量,这项特征称之为"语法域"。
假如有这样一个例子:

--根据年级对姓名进行排序  
names = {"peter","paul","marry"}  
grades = {marry = 10,paul = 7,peter = 8}  
  
table.sort(names,function (n1,n2)  
return grades[n1] > grades[n2]        
end)  
  
for i,v in ipairs(names) do  
print(v)                      --marry peter paul  
end  
现在要用一个函数来完成上面的排序,即对排序函数进行封装:

--根据年级对姓名进行排序  
names = {"peter","paul","marry"}  
grades = {marry = 10,paul = 7,peter = 8}  
  
--[[table.sort(names,function (n1,n2)  
return grades[n1] > grades[n2]        
end)--]]  
  
function sortByGrade(names,grades)  
    table.sort(names,function (n1,n2)  
    return grades[n1] > grades[n2]  
    end)  
end  
  
sortByGrade(names,grades)  
for i,v in ipairs(names) do  
print(v)                      --marry peter paul  
end  
可以发现sort的匿名参数可以访问grades,而grades是外部函数sortByGrade的局部变量。在这个匿名函数的内部,grades既不是全局变量也不是局部变量,将其称为一个"非局部的变量"。

再来看看这个:

function count()  
    local i = 0  
    return function()  
        i = i + 1  
        return i  
    end  
end  
  
c = count()  
print(c())                  --1  
print(c())                  --2  


在这段代码中,匿名函数访问了一个"非局部的变量"i,该变量用于保持一个计数器。初看上去,由于创建变量i的函数(count)已经返回,所以之后每次调用匿名函数时,i都应该是超出了作用范围的,但其实不然,lua会以closure(闭合函数)的概念来正确地处理这种情况。简单地讲,一个closure(闭合函数)就是一个函数加上该函数所需访问的所有"非局部的变量"。就以上例而言,closure(闭合函数)就是匿名函数加上变量i。对上例进一步修改:

function count()    
    local i = 0    
    return function()    
        i = i + 1    
        return i    
    end    
end    
    
c = count()    
print(c())                  --1    
print(c())                  --2    
  
c2 = count()    
print(c2())                 --1  
print(c())                  --3  
print(c2())                 --2    
因此c和c2是同一个函数所创建的两个不同的closure,它们各自拥有局部变量i的独立实例。
从技术上来讲,lua中只有closure,而不存在"函数",因为函数本身就是一种特殊的closure。不过只要不会引起混淆,仍将采用"函数"来指代closure。


非全局的函数:
由于函数是一种"第一类值",因此一个显而易见的推论就是,函数不仅可以存储在全局变量中,还可以存储在table的字段中和局部变量中。
a = {}  
  
a.foo = function (x,y)  
    return x + y  
end  
  
a.goo = function (x,y)  
    return x - y  
end  
  
print(a.foo(1,2))                --3  
print(a.goo(4,3))                --1  
  
---------------------------------------------------  
  
b = {  
    foo = function(x,y) return x + y end,  
    goo = function(x,y) return x - y end,  
}  
  
print(b.foo(1,2))                --3  
print(b.goo(4,3))                --1  
  
---------------------------------------------------  
  
c = {}  
  
function c.foo(x,y) return x + y end  
function c.goo(x,y) return x - y end  
  
print(c.foo(1,2))                --3  
print(c.goo(4,3))                --1  
只要将一个函数存储到一个局部变量中,即得到了一个"局部函数",也就是说该函数只能在某个特定的作用域中使用。

六.协同程序
协同程序跟线程差不多,区别在于:
一个具有多个线程的程序可以同时运行几个线程;
一个具有多个协程的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起(suspend)时,它的执行才会暂停。
一个协同程序可以处于4种不同的状态:挂起(suspended)、运行(running)、死亡(dead)和正常(normal)。

当创建一个协同程序时,它处于挂起状态,不会自动执行其内容。


lua将所有关于协同程序的函数放置在一个名为"coroutine"的table中:
函数create用于创建新的协同程序,它只有一个参数,就是一个函数。该函数的代码就是协同程序所需执行的内容。create会返回一个thread类型的值,用以表示新的协同程序。通常create的参数是一个匿名函数。
函数status可以用来检查协同程序的状态。
函数resume用于启动或再次启动一个协同程序,并将其状态由挂起改为运行。

co = coroutine.create(function ()  
    print("hi")  
end)  
  
print(co)                         --thread: 002FC6B8  
print(coroutine.status(co))       --suspended  
coroutine.resume(co)              --hi  
print(coroutine.status(co))       --dead  


协同程序的强大之处在于函数yield的使用,该函数可以让一个运行中的协同程序挂起,而之后可以再恢复它的运行。

co = coroutine.create(function ()  
    for i = 1,10 do               --默认递增1  
        print("hi",i)  
        coroutine.yield()  
    end  
end)  
  
print(coroutine.status(co))       --suspended  
  
coroutine.resume(co)              --hi    1  
print(coroutine.status(co))       --suspended  
  
coroutine.resume(co)              --hi    2  
print(coroutine.status(co))       --suspended  


当一个协同程序A唤醒另一个协同程序B时,协同程序A就处于一种特殊的状态,既不是挂起状态(A无法执行),也不是运行状态(是B在运行)。所以将此时的状态称为正常状态。

yield也是有返回值的:

co = coroutine.create(function (a,b,c)  
    print("hi",a,b,c)  
end)  
  
coroutine.resume(co,1,2,3)              --hi 1 2 3  
print(coroutine.resume(co,1,2,3))       --false cannot resume dead coroutine  
  
-------------------------------------------------------  
  
co = coroutine.create(function (a,b)  
    coroutine.yield(a + b,a - b)  
end)  
  
print(coroutine.resume(co,20,10))       --true 30 10  
                                        --true表示没有错误  
-------------------------------------------------------  
  
co = coroutine.create(function ()  
    print("hi",coroutine.yield())  
end)  
  
print(coroutine.status(co))             --suspended  
coroutine.resume(co,2,3)                --无输出,因为被挂起了  
print(coroutine.status(co))             --suspended  
coroutine.resume(co,4,5)                --hi 4 5,yield的返回值是对应的resume的传入值  
print(coroutine.status(co))             --dead  
  
-------------------------------------------------------  
  
co = coroutine.create(function ()  
    return 6,7  
end)  
  
print(coroutine.resume(co))              --true 6 7  

------

最后,再次声明:转自http://blog.youkuaiyun.com/lyh916/article/details/49755339,请点击链接查看原文,尊重楼主版权。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值