[Unity热更新]lua基础(二)
2015-11-10 14:43
288 查看
五.函数
在lua中,若一个函数只有一个参数,并且此参数是一个字符串或table构造式,那么圆括号便可不写。
print "hello world" --等同于print("hello world")
print {10,20} --等同于print({10,20})
多重返回值:lua允许函数返回多个结果。根据情况,函数返回值的个数也不同
a.若将函数作为表达式的一部分来调用时,只保留函数的第一个返回值
b.当一个函数调用是一系列表达式中的最后一个元素(或仅有一个元素)时,才能获得函数的所有返回值
这里的"一系列表达式"在lua中表现为4种情况:多重赋值、函数调用时传入的实参列表、table的构造式和return语句
变长参数:
前面提到,函数是可以存储在变量中的。函数与其他所有值都是匿名的,即它们都没有名称。当讨论一个函数名时,实际上是在讨论一个持有某函数的变量。
所以对于:
function foo(x) return 2*x end
其实就是等于:
foo = function (x) return 2*x end
若将一个函数写在另一个函数之内,那么这个位于内部的函数便可以访问外部函数中的局部变量,这项特征称之为"语法域"。
假如有这样一个例子:
现在要用一个函数来完成上面的排序,即对排序函数进行封装:
可以发现sort的匿名参数可以访问grades,而grades是外部函数sortByGrade的局部变量。在这个匿名函数的内部,grades既不是全局变量也不是局部变量,将其称为一个"非局部的变量"。
再来看看这个:
在这段代码中,匿名函数访问了一个"非局部的变量"i,该变量用于保持一个计数器。初看上去,由于创建变量i的函数(count)已经返回,所以之后每次调用匿名函数时,i都应该是超出了作用范围的,但其实不然,lua会以closure(闭合函数)的概念来正确地处理这种情况。简单地讲,一个closure(闭合函数)就是一个函数加上该函数所需访问的所有"非局部的变量"。就以上例而言,closure(闭合函数)就是匿名函数加上变量i。对上例进一步修改:
因此c和c2是同一个函数所创建的两个不同的closure,它们各自拥有局部变量i的独立实例。
从技术上来讲,lua中只有closure,而不存在"函数",因为函数本身就是一种特殊的closure。不过只要不会引起混淆,仍将采用"函数"来指代closure。
非全局的函数:
由于函数是一种"第一类值",因此一个显而易见的推论就是,函数不仅可以存储在全局变量中,还可以存储在table的字段中和局部变量中。
只要将一个函数存储到一个局部变量中,即得到了一个"局部函数",也就是说该函数只能在某个特定的作用域中使用。
六.协同程序
协同程序跟线程差不多,区别在于:
一个具有多个线程的程序可以同时运行几个线程;
一个具有多个协程的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起(suspend)时,它的执行才会暂停。
一个协同程序可以处于4种不同的状态:挂起(suspended)、运行(running)、死亡(dead)和正常(normal)。当创建一个协同程序时,它处于挂起状态,不会自动执行其内容。
lua将所有关于协同程序的函数放置在一个名为"coroutine"的table中:
函数create用于创建新的协同程序,它只有一个参数,就是一个函数。该函数的代码就是协同程序所需执行的内容。create会返回一个thread类型的值,用以表示新的协同程序。通常create的参数是一个匿名函数。
函数status可以用来检查协同程序的状态。
函数resume用于启动或再次启动一个协同程序,并将其状态由挂起改为运行。
协同程序的强大之处在于函数yield的使用,该函数可以让一个运行中的协同程序挂起,而之后可以再恢复它的运行。
当一个协同程序A唤醒另一个协同程序B时,协同程序A就处于一种特殊的状态,既不是挂起状态(A无法执行),也不是运行状态(是B在运行)。所以将此时的状态称为正常状态。
yield也是有返回值的:
在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
前面提到,函数是可以存储在变量中的。函数与其他所有值都是匿名的,即它们都没有名称。当讨论一个函数名时,实际上是在讨论一个持有某函数的变量。
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
相关文章推荐
- 详解Lua中的表的概念及其相关操作方法
- Lua编程示例(二):面向对象、metatable对表进行扩展
- 把Lua编译进nginx步骤方法
- Lua脚本自动生成APK包
- Lua中的元表(metatable)、元方法(metamethod)详解
- Lua中的metatable介绍
- Lua中ipair和pair的区别
- Lua中的函数精讲笔记
- 浅谈Lua的面向对象特性
- 详解Lua中的变量相关知识点
- Lua脚本语言入门笔记
- Lua脚本调用外部脚本
- 详解Lua中的if语句的使用方法
- Lua中调用函数使用点号和冒号的区别
- Lua中的闭合函数、非全局函数与函数的尾调用详解
- Lua中强大的元方法__index详解
- Lua中调用C++函数示例
- Lua面向对象之类和继承浅析
- Lua性能优化技巧(一):前言
- Lua中获取table长度问题探讨