Lua函数进阶

函数是值类型

《programming in lua》里面举了一个非常生动的例子:

a = {p = print} 
a.p("Hello World") --> Hello World 
print = math.sin -- `print' now refers to the sine function 
a.p(print(1)) --> 0.841470 
sin = a.p -- `sin' now refers to the print function 
sin(10, 20) --> 10 20

意味着当我们把函数变量指向另一个函数的时候,原地址依然保存着那份函数,可以用其他变量名指向这个函数,并接着调用。

高级函数

table.sort实际上就是一个典型的高级函数,其第二个参数即是function类型的,用于确定两个值哪个值应当在前:

table.sort(list,function(a,b)
    return a > b
end)

词法定界&闭包

这是我认为lua最灵活强大的功能之一。

词法定界的意思即是,局部函数内部可以访问局部函数外部的变量:

bAscending = true
a = {2,3,1,6,7,8}
table.sort(a,function(num1,num2)
    if bAscending then
        return num1 < num2
    else
        return num1 > num2
    end
end)
for i = 1,#a do
    print(a[i])
end

如上,bAscending可以在比较函数外面被访问到。

官方文档中一个更有意思的示例代码,我修改了一点以更清晰:

function newCounter() 
    local i = 0 
    local f = function() -- anonymous function 
        i = i + 1
        return i
    end
    print(f)
    return f
end
c1 = newCounter() --> function: 000001A8D24EB820
print(c1()) --> 1 
print(c1()) --> 2
c2 = newCounter() --> function: 000001A8D24EBAC0
print(c2()) --> 1 
print(c1()) --> 3 
print(c2()) --> 2

再略微修改上方的一些代码,观察输出:

function newCounter() 
    local i = 0 
    local f = function() -- anonymous function 
        i = i + 1
        return i
    end
    print(f)
    return f
end
c1 = newCounter --> 
print(c1()) --> function: 000001D128558270 function: 000001D128558270
print(c1()) --> function: 000001D128558840 function: 000001D128558840
c2 = newCounter --> 
print(c2()) --> function: 000001D1285583F0 function: 000001D1285583F0
print(c1()) --> function: 000001D128558600 function: 000001D128558600
print(c2()) --> function: 000001D1285582A0 function: 000001D1285582A0

发现不一样的地方了吗?

有几点我们需要额外注意:

  1. 第一段代码的c1和c2最终其实都是闭包函数本身,在初始化的第一时间,就执行了print(f)的操作,自此之后,c1和c2就是f,所以print(c1())实际就是print(f())
  2. c1和c2初始化时的f相当于是开创的新变量,其指向的是全新的值,所以可以看到初始化时候的print(f)显示的地址是新地址,而且执行c1()和c2()的计数是完全独立,不受影响的
  3. 第二段代码的c1和c2实际是newCounter函数,所以第一时间没有输出值,而执行print(c1()) or print(c2())函数时print了两个完全相同的地址,其实也很好理解,相当于每次执行newCounter,其内部print了一次闭包函数地址,返回的又是此函数的地址,所以print了两次一样的值。
  4. 第二段代码每一次print出来的function地址都不一致,意味着每次执行这个函数,闭包函数地址都会变,进一步解释了第二条的计数完全独立的原因。

尾调用

很简单的一个概念,即return一个新函数时,不开辟额外栈空间去单独执行,而更类似于goto的状态转换。计算机基础里面有提到过,函数内部调用函数相当于开辟一个栈空间去执行,以此类推,直到一层层返回值即一层层清除栈空间,所以会有“调用函数会占空间”的这么一个说法。但是如下示例时:

function f(x) 
    return g(x) 
end

lua解释器利用“调用g后不会再做任何事情,这种情况下当被调用函数g结束时程序不需要返回到调用者f”的特性,直接采用类似goto的做法跳转到g(x)执行,所以理论上尾调用递归的层次可以无限制的。但是需要分清什么是尾调用,只有return g(...)的情况才是,任何其他情况比如先g(...)再return,或者return g(...)+1这种都需要开辟额外栈空间。

你可能感兴趣的:(unity,热更新,lua)