美文网首页Lua教程
Lua极简入门(七)——函数高级特性(闭包)

Lua极简入门(七)——函数高级特性(闭包)

作者: 李小磊_0867 | 来源:发表于2019-11-01 11:29 被阅读0次
  • 闭包

当出现一个函数内嵌套另一个函数时,嵌套函数可以访问父函数的数据及资源,称为闭包Lua的闭包原则就是一个函数加上该函数所需要访问的所有变量形成闭包函数

function multip()
    local i = 0
    m = function()
        i = i + 1
        return i * i
    end

    return m
end

m1 = multip()
m2 = multip()
print(m1())
-->> 1
print(m1())
-->> 4
print(m2())
-->> 1
print(m1())
-->> 9
print(m2())
-->> 4

在这个例子中,如果按照常规的想法,i在调用multip()后已经超出了m函数的作用范围内,是无法在读取该变量的,但对于程序执行来说,i变量随着m函数一起被封包返回,因此不断调用m1时,i不断累加,其平方值会不断累增。另外当调用多次multip()创建多个函数变量时,各自的i变量累加并不互相影响,这说明每次调用multip函数时,都创建了一个新的闭包函数,每个闭包函数都各自维护了所需的变量i。和闭包的定义相互验证。

在之前的章节中,利用Lua函数闭包实现了延迟执行的特性。利用延迟执行可以实现很多功能,比如类似JavaScript中的Callback。班级内进行了一次期中考试,在页面上展示了班级内的学生列表信息,当教师点击学生姓名按钮时,将展示学生的考分以及班级排名。这种需求利用闭包将非常容易实现,在这个需求中,页面上的学生列表都是一致的,因此可以设计一个对象,包含了用户名,同时提供一个回调函数,这样姓名+查询函数将形成一个闭包,并且,对于班级内全部学生,其生成的方式是一致的。

scores = {
    { name = "张三", score = 98 },
    { name = "李四", score = 78 },
    { name = "王五", score = 89 },
    { name = "钱七", score = 65 },
    { name = "赵赵", score = 99 }
}

table.sort(scores, function(n1, n2)
    return n1.score > n2.score
end)

function rank(name)
    local exist = false
    for i, v in pairs(scores) do
        if name == v.name then
            exist = true
            print("分数=" .. v.score .. ",排名=" .. i)
            break
        end
    end
    if not exist then
        print("学生[" .. name .. "]不存在")
    end
end

function student(name)
    return {
        show = function()
            print("查询的学生:" .. name)
        end,
        rank = function()
            return rank(name)
        end
    }
end

s1 = student("张三")
s1.show()
s1.rank()
-->> 查询的学生:张三
-->> 分数=98,排名=2
s2 = student("qq")
s2.show()
s2.rank()
-->> 查询的学生:qq
-->> 学生[qq]不存在

在这个班级学生成绩查询系统中,scores为学生成绩数据库,是学生姓名和成绩组成的对象集合;student是生成页面学生列表的基础对象,其show函数演示了生成对象后,并在页面生成一个学生姓名按钮的展示动作;当教师点击学生姓名按钮时,该按钮将触发其rank查询动作;rank中已经将其所需的资源进行了封包。

在本文开头处,介绍了Lua的函数都是存储在变量中,函数名只是指向了函数时,将绝对值函数指向了print变量,从而使得print可以执行绝对值的操作,替代了原有的打印函数。但是按这种操作方式,在这个运行时内,Lua将丢失了对打印函数的指向,如果要还原,还需要重启Lua,或者将打印函数保存到其他变量,再重新指向。如果只是在某些场景下需要这样操作,可以利用闭包实现,而在其他场景中pirnt功能不变。

function print2(val)
    p = print
    local print = math.abs
    p(val .. "绝对值=" .. print(val))
end

print2(-9)
print("-9绝对值=" .. math.abs(-9))
-->> -9绝对值=9
-->> -9绝对值=9

这种特性非常有使用场景,在特定需求下,Lua的这种设计比Java更好。如果要让内置函数完成一些操作,然后再执行原有功能,比如执行文件读取时,先记录一下日志,就可以通过上述的方式,对内置函数进行改写,如下面的伪码示例:

function r()
    local open = io.open
    io.open = function(参数)
        log("读取日志")
        open(参数)
    end
end

这种特性对系统升级也有挺重要的帮助,以之前学生成绩查看系统为例,当系统运行中,发现有学生使用了该系统,并查看了各个同学的成绩和排名,造成了成绩较差学生的心理负担,现在开发接手,要添加一个权限验证方案,从session中获取用户身份,如果为老师,则提供该功能,如果是学生则不能查看成绩和排名。

-- 添加新的权限,不修改原有函数,覆盖了rank函数,并提供了Session中身份的校验,原有调用都不变
local srcRank = rank
rank = function(name)
    if teacher == "教师" then
        return srcRank(name)
    else
        print("没有权限不能查看学生成绩")
    end
end
-- 重新测试,并模拟读取Session的教师身份
s1 = student("张三")
s1.show()
s1.rank()
-->> 查询的学生:张三
-->> 没有权限不能查看学生成绩
teacher = "教师"  -->> Session模拟
s2 = student("王五")
s2.show()
s2.rank()
-->> 查询的学生:王五
-->> 分数=89,排名=3

相关文章

  • Lua极简入门(七)——函数高级特性(闭包)

    闭包 当出现一个函数内嵌套另一个函数时,嵌套函数可以访问父函数的数据及资源,称为闭包。Lua的闭包原则就是一个函数...

  • Lua极简入门(七)——函数高级特性

    在Lua中函数和其他类型的值具有相同权利,如函数和数值、字符串等具有相同地位。因此函数也可以像其他类型一样存储到变...

  • Lua语言学习教程

    lua闭包 函数尾调用 迭代器

  • 你一定看得懂的 —— 闭包

    Js 是一门完整的面向对象语言,同时也有 函数式语言特性。其中 就有 闭包和高级函数。 听到 闭包,你会想到什么?...

  • 简单详细讲解js闭包(看完不懂你砍我!!!)

    《javascript高级程序设计》中闭包的概念: 闭包,其实是一种语言特性,它是指的是程序设计语言中,允许将函数...

  • lua闭包函数

    简单释义:函数里套函数,里层函数可以访问外层函数的所有局部 变量 1,lua中函数是第一类值 (他们可以存储在变量...

  • Lua极简入门(六)——函数

    在完成一些编码工作时,总会有一些相似或者重复的工作。比如在结算工资时,员工的工资不同,但缴纳税、社保等计算是一个相...

  • 闭包理解(个人笔记)

    闭包 闭包 是指有权访问另一个函数作用域中的变量的函数(JavaScript高级程序设计)闭包:函数A内部有函数B...

  • js闭包

    闭包的定义 闭包就是能够读取其他函数内部变量的函数 闭包的特性 封闭性:外界无法访问闭包内部的数据,如果在闭...

  • js面试题

    JS中闭包的特性及其优缺点 闭包有三个特性: 函数嵌套函数。 函数内部可以引用外部的参数和变量。 参数和变量不会被...

网友评论

    本文标题:Lua极简入门(七)——函数高级特性(闭包)

    本文链接:https://www.haomeiwen.com/subject/grjfbctx.html