• Lua更多语法与使用


    目的

    在前一篇文章: 《Lua入门使用与基础语法》 中介绍了一些基础的内容。这里将继续介绍Lua一些更多的内容。

    同样的本文参考自官方手册:
    https://www.lua.org/manual/

    错误处理

    下面代码可以直接测试相关内容:

    -- 使用 assert (v [, message]) 可以检查条件v,如果失败则抛出错误信息message
    
    --[[
    使用 error (message [, level]) 抛出错误信息message
    level为1时(默认值)会在message头部添加调用error函数的位置信息;
    level为2时会添加调用error的函数被调用的位置信息;
    level为0时不添加额外信息。
    ]]
    
    -- 使用 pcall() (f [, arg1, ···]) 执行函数并捕获可能的错误。执行无错误返回true,否则返回false和错误对象。
    
    function func1(arg)
      error(arg) -- 抛出错误
    end
    
    ret, msg = pcall(func1, "hello naisu!")
    print("pcall: ", ret, msg)
    
    -- xpcall (f, msgh [, arg1, ···]) 和pcall类似,第二个参数为错误处理函数
    
    function func2()
      print(debug.traceback())
    end
    
    ret, msg = xpcall(func1, func2, "hello naisu!")
    print("xpcall: ", ret, msg)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    元表和元方法

    Lua中可以给值(变量)添加一个原表,元表中可以是各种元方法。元方法用于改变该对象的默认行为,比如该对象运算时的行为,格式化输出时的行为等。

    使用 setmetatable (table, metatable) 方法向 table 添加一个 metatablemetatablenil 时用于移除元表;使用 getmetatable (object) 返回对象的原表。

    常见的运算相关元方法如下:

    元方法运算元方法运算元方法运算元方法运算
    __add+__sub-__mul*__div/
    __mod%__pow^__unm-__idiv//
    __band&__bor|__bxor~(异或)__bnot~(非)
    __shl<<__shr>>__concat__len#
    __eq==__lt<__le<=

    除了上面一些基础的运算相关的元方法,Lua中还有更多元方法,下面是个基本的测试:

    --[[ 下面是__index ]]
    print("__index:")
    
    t1 = setmetatable({ a=22 },{ __index = function() return 33 end})
    
    print(t1.a)
    print(t1.b) -- 访问不存在的元素
    
    t2 = setmetatable({ a=22 },{ __index = { b=33 }})
    
    print(t2.a)
    print(t2.b) -- 访问不存在的元素
    print(t2.c) -- 访问不存在的元素
    
    
    --[[ 下面是__newindex ]]
    print("__newindex:")
    
    t3 = setmetatable({ a=22 },{ __newindex = function (table, key, value) print(#table, key, value) end})
    
    print(t3.a)
    t3.b = 33   -- 设置不存在的元素时会调用__newindex
    print(t3.b) -- __newindex是函数时,值并不会设置到table中
    
    t4 = setmetatable({ a=22 },{ __newindex = function (table, key, value) rawset(table, key, value * 2) end})
    
    print(t4.a)
    t4.b = 33   -- 设置不存在的元素时会调用__newindex
    print(t4.b) -- rawset方法将新元素添加到table中
    
    t5 = {}
    t6 = setmetatable({ a=22 },{ __newindex = t5})
    t6.b = 33
    print(t6.b) -- __newindex是表时,设置不存在的元素,值并不会设置到table中
    print(t5.b) -- __newindex是表时,设置不存在的元素,值会设置到元表中
    
    
    --[[ 下面是__call ]]
    print("__call:")
    
    t7 = setmetatable({ a=22 },{ __call = function (table, value) print(table.a, value) end})
    
    t7(33) -- __call方法会在把表当函数用的时候被调用
    
    
    --[[ 下面是__close ]]
    print("__close:")
    
    t8 = setmetatable({ a=22 },{ __close = function (table) print(table.a)  end})
    
    do
      local var<close> = t8
    end
    -- close属性的变量会在退出其作用域时调用__close方法
    
    --[[ 下面是__tostring ]]
    print("__tostring:")
    
    t9 = setmetatable({ a=22 },{ __tostring = function (table) return "value: "..table.a end})
    
    print(tostring(t9)) -- __tostring方法会在使用tostring函数时被调用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    垃圾回收

    Lua是带垃圾回收功能的,通常不用手动去控制它,如果有特殊需求的话可以使用 collectgarbage ([opt [, arg]]) 方法来手动控制垃圾收集器。比如使用 collectgarbage("collect") 进行一次完整的垃圾回收、使用 collectgarbage("count") 获得Lua占用的内存数据(单位为1024字节)。

    另外如果一个表被其他表引用的话,该表不会被回收,可以用过弱表来处理该情况:

    t1 = {}
    
    setmetatable(t1, {__mode = "k"}) -- 设置表的key为弱类型
    
    k1 = {}
    t1[k1] = 22
    k2 = {}
    t1[k2] = 33
    k1 = nil    -- 将k1删除,k1引用的那个表只存在于t1,但t1是key弱引用,所以这个表将被GC
    
    collectgarbage() -- 强制执行一次GC
    for k, v in pairs(t1) do print(v) end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    协程

    Lua中的协程和大多数语言中的协程差不多,提供了一些协程创建、启动、挂起等方法,协程需要主动交出控制权。

    • coroutine.create (f)
      传入函数创建协程返回协程句柄;
    • coroutine.resume (co [, val1, ···])
      运行协程,传入协程句柄和参数;成功时返回true和返回值;失败时返回false和错误信息;
    • coroutine.yield (···)
      协程主动暂停,输入的参数是传递给resume的返回值;
    • coroutine.close (co)
      关闭协程
    • coroutine.wrap (f)
      传入函数创建协程返回函数,调用该函数相当于调用resume;
    • coroutine.isyieldable ([co])
    • coroutine.running ()
      返回正在运行的协程加上一个布尔值,当正在运行的协程是主协程时为true。
    • coroutine.status (co)

    下面代码是个简单的测试:

    function func()
      print("协同程序 func 开始执行")
      local value = coroutine.yield("暂停 func 的执行")
      print("协同程序 func 恢复执行,传入的值为: " .. tostring(value))
      print("协同程序 func 结束执行")
    end
    
    -- 创建协同程序
    local co = coroutine.create(func)
    
    -- 启动协同程序
    local status, result = coroutine.resume(co)
    print(result) -- 输出: 暂停 func 的执行
    
    -- 恢复协同程序的执行,并传入一个值
    status, result = coroutine.resume(co, 233)
    print(result) -- 输出: 协同程序 func 恢复执行,传入的值为: 233
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    模块

    当需要多个文件组合实现功能时就涉及到模块的概念的,简单理解就是一个文件引用其他文件:
    在这里插入图片描述

    面向对象

    Lua也支持面向对象的方式,本质其实就是table中同时放变量和函数等。稍稍比table使用多一点的内容是可以使用 : 来定义个使用table中的函数,这样这个函数内部默认会有一个指向自身的 self 对象。

    下面代码可以直接测试相关内容:

    Class = {}
    
    function Class:new(name) -- 注意这里内部的操作,这个方法相当于构造函数
      obj = {}
      setmetatable(obj,self)
      self.__index = self
      self.name = name
      return obj
    end
    
    function Class:printName()
      print(self.name);
    end
    
    obj1 = Class:new("naisu") -- 新建一个对象
    
    print(obj1.name) -- 使用 . 访问属性
    obj1:printName() -- 使用 : 调用方法
    
    obj2 = Class:new("nx233") 
    obj2:printName()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    总结

    上面的一些Lua的语法功能使得Lua更加灵活和完善,不单单作为脚本,进行大型项目开发也可一用。

  • 相关阅读:
    iEnglish全国ETP大赛:教育游戏助力英语习得
    Java入门-Java语言概述
    数据结构入门(C语言版)图的概念和功能函数实现
    mysql存储过程
    c高级day2 linux指令的补充和shell脚本
    对NFT许可的观察:事实与虚构
    Neutron — DHCP Agent 实现原理
    131个经典面试题目+答案
    Vue 3的组合式API:你真的需要它吗?
    前端常用的开发工具有哪些?
  • 原文地址:https://blog.csdn.net/Naisu_kun/article/details/132990355