美文网首页Lua
Lua基础知识

Lua基础知识

作者: ClownWang | 来源:发表于2020-02-25 15:38 被阅读0次

    1.模块与包

    • 基础知识

    • 模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
    • Lua 的模块是由变量、函数等已知元素组成的 table。
    local module = {}
    -- 定义一个常量
    module.constant = "这是一个常量"
    -- 定义一个函数
    function module.func1()
        io.write("这是一个公有函数!\n")
    end
    local function func2()
        print("这是一个私有函数!")
    end
    return module
    
    • Lua提供了一个名为require的函数用来加载模块。 require()函数先检测package.loaded表中是否存在module_name,若存在则直接返回当中的值,若不存在则通过定义的加载器加载module_name。
    function require(module)
        -- 判断模块是否已经被加载
        if not package.loaded[module] then
            -- 获取模块的加载器
            local loader = findloader(module)
            if loader==nil then
                error("unable to load module "..module)
            end
            -- 将模块标记为已加载
            package.loaded[module] = true
            -- 初始化模块
            local result = loader(module)
            if result~=nil then
                package.loaded[module] = result
            end
        end
        return package.loaded[module]
    end
    
    • Lua提供require()函数用来加载运行库,require()和dofile()完成相同的功能,不同点是
      require会搜索目录以加载文件
      require不会重复加载同一模块
      若要让每次加载文件都执行,可使用dofile。
      若加载后不执行,等需要时执行,可使用loadfile。

    问题

    -代码内更新可以很好的利用此机制。

    2. 元表与元方法

    基础知识

    • 在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作。因此 Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。

    • 举例来说,当一个非数字的值作加法操作的时候, Lua 会检查它的 metatable 中 "__add" 域中的是否有一个函数。 如果有这么一个函数的话,Lua 调用这个函数来执行一次加法。

    • 我们叫 metatable 中的键名为 事件 (event) ,把其中的值叫作 元方法 (metamethod)。 在上个例子中,事件是 "add" 而元方法就是那个执行加法操作的函数。

    • 可以通过 getmetatable 函数来查询到任何一个值的 metatable。

    • 可以通过 setmetatable 函数来替换掉 table 的 metatable 。

    • 元方法 __index 用来对表访问,访问规则:
      1.在表中查找,如果找到,返回该元素,找不到则继续。
      2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
      3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。

    • 元方法 __newindex 用来对表更新,更新规则:
      1.如果是表已存在的索引键,则直接更新,没有的话就继续。
      2.解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
      3.如果不存在则直接对表赋值。

    问题

    • 因为Lua本身是没有面向对象支持的,但在项目开发中需要面向对象编程,于是很多人用Lua本身的数据结构table+元表来模拟面向对象实现类、继承、多重继承。当元方法 __index__newindex 变成函数时,会因为 函数本身的复杂度导致逻辑消耗时间变多。在大型项目里是不小的性能开销。

    3. 弱引用Table

    基础知识

    • Lua有着自己的自动内存管理。程序只需要负责创建对象,而不需要去删除对象。通过垃圾回收机制,lua会自动去删除那些已经成为垃圾的对象。但问题在垃圾收集器只能回收那些它认为是垃圾的东西,不会回收那些用户认为是垃圾的东西。比如那些存储在全局变量中的对象,即使程序不会再用到它们,但对于Lua来说它们也不是垃圾,除非用户将这些对象赋值为nil,这样它们才能被释放。但有时候,简单地清除引用还不够,比如将一个对象放在一个数组中时,它就无法被回收,这是因为即使当前没有其他地方在使用它,但数组仍引用着它,除非用户告诉Lua这项引用不应该阻碍此对象的回收,否则Lua是无从得知的。
    • table中有key和value,这两者都可以包含任意类型的对象。通常,垃圾收集器不会回收一个可访问table中作为key或value的对象。也就是说,这些key和value都是强引用,它们会阻止对其所引用对象的回收。在一个弱引用table中,key和value是可以回收的。
    • 弱引用table(weak table)是用户用来告诉Lua一个引用不应该阻碍对该对象的回收。所谓弱引用,就是一种会被垃圾收集器忽视的对象引用。如果一个对象的引用都是弱引用,该对象也会被回收,并且还可以以某种形式来删除这些弱引用本身。
      对于弱引用table,其实有三种形式:
      1.key值弱引用,也就是刚刚说到的情况,只要其他地方没有对key值引用,那么,table自身的这个字段也会被删除。设置方法:setmetatable(t, {__mode = “k”});
      2.value值弱引用,情况类似,只要其他地方没有对value值引用,那么,table的这个value所在的字段也会被删除。设置方法:setmetatable(t, {__mode = “v”});
      3.key和value弱引用,规则一样,但是key和value都同时生效,任意一个起作用时都会导致table的字段被删除。设置方法:setmetatable(t, {__mode = “kv”});
    local t = {};
    --setmetatable(t, {__mode = "k"}) --key值弱引用
    --setmetatable(t, {__mode = "v"}) --value值弱引用
    --setmetatable(t, {__mode = "kv"}) --key和value弱引用
    
    -- 使用一个table作为t的key值
    local key = {name = "key"}
    t[key] = key
    key = nil
    
    -- 使用一个table作为t的key值
    local value = {name = "value"}
    t["value"] = value
    value = nil
    
    -- 强制进行一次垃圾收集
    collectgarbage();
        
    for key, value in pairs(t) do
        print(value.name)
    end
    

    问题

    • 弱引用就是一种这样的机制。实际代码开发中还是强引用的,需要开发者管理好引用关系减少gc。

    相关文章

      网友评论

        本文标题:Lua基础知识

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