• require、loadfile、dofile、load、loadstring


    1.loadfile只编译,不运行
    loadfile(filename, mode, env) 用于加载一个指定路径filename的代码块,参数如下:
    在这里插入图片描述
    基本和load等同,区别是用来加载一个文件的代码块,参见如下:

    LuaFunc.lua(被访问)文件:

    --LuaFunc.lua
    function add(x, y)
        return x + y
    end
     
    m = "LuaFunc.m"
    local n = "n"
     
    print("------------------ < LuaFunc.lua > ------------------")
    print("m = "..m)
    print("n = "..n)
    print("------------------ < LuaFunc.lua > ------------------")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    调用代码如下:

    --加载并编译代码
    f = assert(loadfile("Child/LuaFunc.lua"))
    --运行
    f()
    print("add : "..add(100, 88))
    print(m)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出结果如下:

    ------------------ < LuaFunc.lua > ------------------
    m = LuaFunc.m
    n = n
    ------------------ < LuaFunc.lua > ------------------
    add : 188
    LuaFunc.m
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • loadfile:只编译,不运行,它只会加载文件,编译代码,不会运行文件里的代码,loadfile只会加载(load)lua文件但是不会执行(run)。比如,我们有一个hellofile.lua文件:
    print(“hello”);
    
    function hehe()
    
    print(“hello”);
    
    end
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这个文件里有一句代码,和一个函数。试试用loadfile加载这个文件,如下代码:

    loadfile("hellofile.lua");
    
    print("end");
    
    • 1
    • 2
    • 3

    输出结果如下:

    end
    
    • 1

    如果说loadfile会执行文件里的代码的话,那么,应该会输出hello字符串的。结果表明,它是不会执行代码的。

    2.dofile执行
    dofile(filename) 用于加载一个指定路径filename的代码块,并运行。参数如下:
    在这里插入图片描述
    内部先调用了loadfile,然后会自动运行一下,参见如下:

    dofile("Child/LuaFunc.lua")
    print("add : "..add(100, 88))
    print(m)
    
    • 1
    • 2
    • 3

    输出与上例等同。

    • 执行dofile就是执行代码,dofile与require类似,但是它没有caching已经执行过一次的文件,所以它可以重复执行多次。很明显,dofile就是会执行代码的家伙了,如下代码:
    dofile("D:/vscode lua代码/hello world/foo.lua");
    
    
    print("end");
    
    • 1
    • 2
    • 3
    • 4

    输出结果如下:

    hello
    end
    
    • 1
    • 2

    3.require我只执行一次
    require(modname) 用于加载一个指定的代码块,并运行。参数如下:
    在这里插入图片描述
    这个函数对于同一个代码块只会加载一次(加载过会保存起来),和dofile类似,加载编译后也会自动运行,参见如下:

    --加载编译并运行
    require("Child/LuaFunc") -- 等同于:require("Child.LuaFunc")
    print("add : "..add(100, 88))
    print(m)
    
    • 1
    • 2
    • 3
    • 4

    输出与上例等同。

    • require和dofile有点像,不过又很不一样,require在第一次加载文件的时候,会执行里面的代码。但是,第二次之后,再次加载文件,则不会重复执行了。换句话说,它会保存已经加载过的文件,不会重复加载。require的返回值会被存储cache起来,所以一个文件最多只会执行一次,即使被require很多次。
    for i = 1, 2, 1 do
       require("foo.lua");
    end
       
    print("end");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    为了说明这种情况,我刻意调用了两次require,输出结果如下:

    hello
    end
    
    • 1
    • 2

    和我们说的一样,调用了两次,但是代码只执行了一次。如果这里换成dofile,则会输出两次hello字符串。

    4.load用于加载字符串代码块
    loadstring,5.2版本之后loadstring被移除,用load代替,load(chunk, chunkname, mode, env) 用于加载字符串代码块,参数如下:
    在这里插入图片描述
    这里要注意:load用于加载字符串代码块并编译,但是并没有运行。在使用前要记得运行一下,参见如下:

    a = 100
    --加载字符串代码块
    f = assert(load("a = a + 100"))
    print("before a = "..a)
    --运行代码块
    f()
    print("after  a = "..a)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果如下:

    before a = 100
    after  a = 200
    
    
    • 1
    • 2
    • 3

    可以看到加载代码块后,在没有运行前,a的值没有发生变化为100,运行后执行了a = a + 100,a = 200

    5.代码块chuck如何理解
    lua中的代码块chunk,实际编译的时候,相当于被一个可变参匿名函数包装,并且会绑定一个唯一的upvalue值_ENV,运行后将代码块chunk中的全局变量添加到了全局环境变量_ENV中。代码块 “a = a + 100” 相当于如下函数:

    --代码块
    function chuck()
        a = a + 100
    end
    --这句是比喻load代码块的加载编译过程(不一定恰当,意会就好)
    f = chuck()
    --运行
    f()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里有些时候可能会疑惑,load中的这段代码块为什么能访问到外部的变量a?

    env:它是一个环境变量,可以自定义(一般用于模拟一个沙盒环境),默认这个值会用lua的全局环境变量_ENV填充。

    _ENVlua5.2版本才有的用来代替_G的一个全局变量(_ENV内部是指向_G的,可以简单的认为他们是同一个东西),但它是一个upvalue值。(_G_ENV感兴趣的可以自行了解)这里简单描述一下_ENV,每一个lua代码块默认都会有一个_ENV全局环境变量,它是一个表,包含了所有的lua标准类库及所有编译过的全局变量。

    a = 100
    --加载并运行字符串代码块
    assert(load("a = a + 11; b = 'b126'; print('this is chunk')"))()
    print("a = "..a)
    print("_ENV.a = ".._ENV.a)
    print("b = "..b)
    print("_ENV.b = ".._ENV.b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出如下:

    this is chunk
    a = 111
    _ENV.a = 111
    b = b126
    _ENV.b = b126
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到:

    1. 代码块中,可以调用print函数,这就是因为默认env传入的是_ENV,相当于调用_ENV.print

    2. a_ENV.a 输出相同,其实在编译的时候,全局变量默认都会在前面加一个_ENV.限定

    3. 编译并运行代码块chunk后,变量b已被加入到_ENV中。

    自定义环境变量env的使用:一般用于模拟一个沙盒环境,参见如下:

    a = 100
    --自定义环境变量
    local env = {
        a = 8,
        print = print
    }
    --加载并运行字符串代码块
    assert(load("a = a + 10; print('this is chunk, a = '..a)", "chunkTest", "bt", env))()
    print("a = "..a)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出如下:

    this is chunk, a = 18
    a = 100
    
    • 1
    • 2
    1. 可以看到代码块chunkTest中,a取的是自定义环境变量enva值,打印a = 18

    2. 因为这里没有用默认全局环境变量_ENV填充,所以外部变量 a 并没有被修改: a = 100

    3. env中的 print = print,等价于:print = _ENV.print

  • 相关阅读:
    无人值守机房浸水监测数据采集网关
    golang中快速用melody搭建轻量的websocket服务
    什么是跨站脚本攻击(XSS)?
    c语言练习86:移除元素
    【华为OD机考B卷 | 100分】整数编码(JAVA题解——也许是全网最详)
    【微信小程序】最新隐私弹窗组件
    软考网络工程师知识点总结(五)
    七大排序:插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序
    学习八股文的知识点~~1
    代码坏味道与重构之霰弹式修改和依恋情结
  • 原文地址:https://blog.csdn.net/qq_44918090/article/details/126021457