Lua 学习笔记

2023年 10月 15日 175.0k 0

参考资料

The Programming Language Lua

Lua 教程 | 菜鸟教程 (runoob.com)

LuatOS 文档

Lua 简介

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于 1993 年开发的,该小组成员有:Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo。

设计目的

其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

一般来说,我们可以使用 C/C++ 来实现功能,而用 Lua 来实现业务逻辑,这样就可以让我们的程序保持高效的同时,又能灵活快速地实现我们的业务。

Lua 特性

  • 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
  • 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
  • 其它特性:
    • 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
    • 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
    • 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
    • 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。

应用场景

  • 游戏开发
  • 独立应用开发
  • Web 应用开发
  • 扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
  • 安全系统,如入侵检测系统

环境安装及运行

Windows

Github 下载 github.com/rjpcomputin…

麻瓜式安装即可,不过只有最新只有 5.1 版本的,有些新特性会不支持。

自行编译安装:

  • www.lua.org/download.ht… 下载最新版本的 Source,我下的就是 lua-5.4.6.tar.gz
  • github.com/skeeto/w64d… 下载 MinGW 用于编译 Lua 的源码
  • 找一个目录比如 D:lua_buildlua-5.4.6 创建 build.bat 内容见后文
  • 修改一下 set lua_version=5.4.6 为你自己的版本
  • 修改 set compiler_bin_dir=C:MinGW-w64mingw64bin 为你自己的 MinGWbin目录
  • 以管理员身份运行 build.bat
  • 正常情况下会出现 lua 目录,就是成功了,然后把 luabin目录配置到环境变量 PATH 里面,就可以使用了
  • @echo off
    :: ========================
    :: file build.cmd
    :: ========================
    setlocal
    :: you may change the following variable's value
    :: to suit the downloaded version
    set lua_version=5.4.6
     
    set work_dir=%~dp0
    :: Removes trailing backslash
    :: to enhance readability in the following steps
    set work_dir=%work_dir:~0,-1%
    set lua_install_dir=%work_dir%lua
    set compiler_bin_dir=C:MinGW-w64mingw64bin
    set lua_build_dir=%work_dir%lua-%lua_version%
     
    cd /D %lua_build_dir%
     
    mingw32-make PLAT=mingw
     
    echo.
    echo **** COMPILATION TERMINATED ****
    echo.
    echo **** BUILDING BINARY DISTRIBUTION ****
    echo.
     
    :: create a clean "binary" installation
    mkdir %lua_install_dir%
    mkdir %lua_install_dir%doc
    mkdir %lua_install_dir%bin
    mkdir %lua_install_dir%include
     
    copy %lua_build_dir%doc*.* %lua_install_dir%doc*.*
    copy %lua_build_dir%src*.exe %lua_install_dir%bin*.*
    copy %lua_build_dir%src*.dll %lua_install_dir%bin*.*
    copy %lua_build_dir%srcluaconf.h %lua_install_dir%include*.*
    copy %lua_build_dir%srclua.h %lua_install_dir%include*.*
    copy %lua_build_dir%srclualib.h %lua_install_dir%include*.*
    copy %lua_build_dir%srclauxlib.h %lua_install_dir%include*.*
    copy %lua_build_dir%srclua.hpp %lua_install_dir%include*.*
     
    echo.
    echo **** BINARY DISTRIBUTION BUILT ****
    echo.
     
    %lua_install_dir%binlua.exe -e"print [[Hello!]];print[[Simple Lua test successful!!!]]"
     
    echo.
     
    pause
    

    Mac

    curl -R -O http://www.lua.org/ftp/lua-5.4.6.tar.gz
    tar zxf lua-5.4.6.tar.gz
    cd lua-5.4.6
    make macos test
    make install
    

    Linux

    curl -R -O http://www.lua.org/ftp/lua-5.4.6.tar.gz
    tar zxf lua-5.4.6.tar.gz
    cd lua-5.4.6
    make linux test
    make install
    

    在线环境

    LuatOS 在线模拟 - lua在线测试

    基本语法

    交互式编程

    Lua 交互式编程模式可以通过命令 lua -ilua 来启用:

    lua -i
    Lua 5.4.6  Copyright (C) 1994-2023 Lua.org, PUC-Rio
    

    脚本式编程

    我们可以创建一个文件 test.lua,输入:

    print("Hello World!")
    

    然后执行下面脚本运行:

    lua test.lua
    

    打印中文的时候如果出现乱码,VSCode 里面 Save with Encoding 可以改为 GBK。

    编译

    使用 luac.lua 编译成字节码,这些字节码可以直接在 Lua 虚拟机上运行,执行效率也更高。

    基本语法:

    luac [ options ] [ file ... ]
    
    luac test.lua
    

    执行之后将会生成一个 luac.out(这是输出文件的默认名称) 文件。

    luac 的常用选项:

    • -o file:指定编译输出的文件名
    • -c:只进行预处理而不进行编译
    • -s:对源代码进行优化
    • -p:预处理源代码但不进行编译优化
    luac -o test.luac teat.lua
    

    执行之后将会生成一个 test.luac 文件。

    编译之后执行方法还是一样的,用 lua 命令即可。

    注释

    -- 单行注释用两个减号
    
    --[[
    多行注释
    多行注释
    --]]
    

    变量

    变量在使用前,需要在代码中进行声明,即创建该变量。

    编译程序执行代码之前编译器需要知道如何给语句变量开辟存储区,用于存储变量的值。

    变量类型

    Lua 变量有三种类型:全局变量、局部变量、表中的域。

    Lua 中的变量全是全局变量,哪怕是语句块或是函数里,除非用 local 显式声明为局部变量。

    全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。

    print(b)
    nil
    b = 10
    print(b)
    10
    

    如果想要删除全局变量,将其赋值为 nil 即可。

    b = nil
    

    局部变量的作用域为从声明位置开始到所在语句块结束。

    变量的默认值均为 nil。

    a = 5       -- 全局变量
    local b = 5 -- 局部变量
    
    function joke()
        c = 5       -- 全局变量
        local d = 6 -- 局部变量
    end
    
    joke()
    print(c, d) --> 5 nil
    
    do
        local a = 6 -- 局部变量
        b = 6       -- 对局部变量重新赋值
        print(a, b); --> 6 6
    end
    
    print(a, b) --> 5 6
    

    赋值语句

    Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。

    a, b = 10, 2
    
    print(a, b) -- 10      2
    

    利用上述特性进行值交换,或将函数调用返回给变量:

    x, y = y, x                     -- swap 'x' for 'y'
    a[i], a[j] = a[j], a[i]         -- swap 'a[i]' for 'a[j]'
    a, b = f()                      -- f()返回两个值,第一个赋给a,第二个赋给b
    

    应该尽可能的使用局部变量,有两个好处:

  • 避免命名冲突。

  • 访问局部变量的速度比全局变量更快。

  • 索引

    对 table 的索引使用方括号 []。Lua 也提供了 . 操作。

    local myArr = {}
    myArr["key1"] = "value1"
    myArr["key2"] = "value2"
    print(myArr["key1"])
    print(myArr.key2)
    

    输出:

    value1
    value2
    

    数据类型

    Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

    8种基础类型如下表所示:

    数据类型 描述
    nil 空,表示无效值,在条件表达式中相当于false
    boolean 布尔值:true和false
    number 数字类型,表示双精度类型的浮点数
    string 字符串,单引号或双引号来表示
    function 由C或Lua编写的函数
    userdata 表示任意存储在变量中的C数据结构
    thread 表示执行的独立线路,用于执行协同程序
    table 表,其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。

    Lua 提供一个 type 函数来检测变量或值的类型:

    print(type("Hello world"))
    print(type(10.4 * 3))
    print(type(print))
    print(type(type))
    print(type(true))
    print(type(nil))
    print(type(type(X)))
    

    输出:

    string
    number
    function
    function
    boolean
    nil
    string
    

    nil

    nil 类型表示空值,给全局变量赋值 nil 等同于把它们删除。

    nil 作比较时应该加上引号:

    if (type(nil)==nil) then
        print(true)
    else
        print(false)
    end
    
    if (type(nil)=="nil") then
        print(true)
    else
        print(false)
    end
    

    输出:

    false
    true
    

    boolean

    布尔类型,Lua 中只把 falsenil 看作假,数字的 0 是真,这与 Javascript 等语言是不一样的。

    number

    默认只有一种数字类型,double 类型。

    string

    字符串,可以用单引号,也可以用双引号来表示。

    string1 = "this is string1"
    string2 = 'this is string2'
    

    字符串块的表示可以使用 [[]]

    html = [[
    
    
    
        

    Hello World

    ]] print(html)

    输出:

    
    
    
        Hello World
    
    
    

    字符串拼接使用 ..,而不是 ++ 是用于数字类型的:

    print("a" .. 'b')
    print(157 .. 428)
    
    print("2" + 6)
    print("2" + "6")
    

    输出:

    ab
    157428
    8
    8
    
    print("abc" + 1) -- 会报错
    

    使用 # 来获取字符串的长度:

    len = "string len"
    print(#len)
    print(#"string len")
    

    输出:

    10
    10
    

    table

    表,也是关联数组,索引可以是数字或者字符串。

    -- 创建一个空的 table
    local tbl1 = {}
     
    -- 直接初始表
    local tbl2 = {"apple", "pear", "orange", "grape"}
    
    print(tbl1)
    print(tbl2[1]) -- 注意不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始。
    

    输出:

    table: 000002109d63a0c0
    apple
    
    local a = {}
    a["key"] = "value"
    a[10] = 11
    for k, v in pairs(a) do
        print(k .. " : " .. v)
    end
    

    输出:

    key : value
    10 : 11
    

    table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 元素 都是 nil

    local a3 = {}
    for i = 1, 10 do
        a3[i] = i
    end
    a3["key"] = "val"
    print(a3["key"])
    print(a3[1])
    print(a3[10])
    print(a3["none"])
    

    输出:

    val
    1
    10
    nil
    

    function

    函数是被看作是"第一类值(First-Class Value)",即函数和变量之间没有区别,函数可以存在变量里。

    local function factorial1(n)
        if n == 0 then
            return 1
        else
            return n * factorial1(n - 1)
        end
    end
    print(factorial1(5))
    local factorial2 = factorial1
    print(factorial2(5))
    

    输出:

    120
    120
    

    function 可以以匿名函数(anonymous function)的方式通过参数传递:

    local function testFun(tab, fun)
        for k, v in pairs(tab) do
            print(fun(k, v));
        end
    end
    
    
    local tab = { key1 = "val1", key2 = "val2" };
    testFun(tab,
        function(key, val) --匿名函数
            return key .. "=" .. val;
        end
    );
    

    输出:

    key1=val1
    key2=val2
    

    thread

    Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。

    线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。

    userdata

    userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。

    流程控制

    if 语句

    --[ 定义变量 --]
    local a = 10;
    --[ 使用 if 语句 --]
    if (a < 20)
    then
        --[ if 条件为 true 时打印以下信息 --]
        print("a 小于 20");
    end
    print("a 的值为:", a);
    

    输出:

    a 小于 20
    a 的值为:       10
    

    if...else 语句

    --[ 定义变量 --]
    local a = 100;
    --[ 检查条件 --]
    if (a < 20)
    then
        --[ if 条件为 true 时执行该语句块 --]
        print("a 小于 20")
    else
        --[ if 条件为 false 时执行该语句块 --]
        print("a 大于 20")
    end
    print("a 的值为 :", a)
    

    输出:

    a 大于 20
    a 的值为 :      100
    

    if...elseif...else 语句

    --[ 定义变量 --]
    local a = 100
    
    --[ 检查布尔条件 --]
    if (a == 10)
    then
        --[ 如果条件为 true 打印以下信息 --]
        print("a 的值为 10")
    elseif (a == 20)
    then
        --[ if else if 条件为 true 时打印以下信息 --]
        print("a 的值为 20")
    elseif (a == 30)
    then
        --[ if else if condition 条件为 true 时打印以下信息 --]
        print("a 的值为 30")
    else
        --[ 以上条件语句没有一个为 true 时打印以下信息 --]
        print("没有匹配 a 的值")
    end
    print("a 的真实值为: ", a)
    

    输出:

    没有匹配 a 的值
    a 的真实值为:   100
    

    循环

    while 循环

    local a = 10
    while (a < 20)
    do
        print("value of a:", a)
        a = a + 1
    end
    

    输出:

    value of a:     10
    value of a:     11
    value of a:     12
    value of a:     13
    value of a:     14
    value of a:     15
    value of a:     16
    value of a:     17
    value of a:     18
    value of a:     19
    

    for 循环

    数值for循环

    for var=exp1,exp2,exp3 do  
          
    end
    

    varexp1 变化到 exp2,每次变化以 exp3 为步长递增,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1。

    for i = 10, 1, -1 do
        print(i)
    end
    

    输出:

    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    

    泛型for循环

    local a = { "one", "two", "three" }
    for i, v in ipairs(a) do
        print(i, v)
    end
    

    输出:

    1       one
    2       two
    3       three
    

    ipairsLua 提供的一个迭代器函数,用了迭代数组

    repeat...until循环

    repeat
       statements
    until( condition )
    

    先执行循环体的语句,再进行条件判断,如果条件为 flase 则继续执行循环体,否则跳出循环。

    local a = 10
    
    repeat
        print("value of a:", a)
        a = a + 1
    until (a > 15)
    

    输出:

    value of a:     10
    value of a:     11
    value of a:     12
    value of a:     13
    value of a:     14
    value of a:     15
    

    循环控制语句

    break语句

    local a = 10
    
    while(a  15) then
            break
        end
    end
    

    执行到 break 处会跳出循环。

    goto语句(5.2+的特性)

    语法:

    goto Label
    

    定义 Label:

    ::Label::
    
    local a = 1
    ::label::
    print("--- goto label ---")
    
    a = a + 1
    if a < 3 then
        goto label -- a 小于 3 的时候跳转到标签 label
    end
    

    输出:

    --- goto label ---
    --- goto label ---
    

    如果 Label 后面需要接多条语句可以用 do...end

    local a = 1
    ::label::
    do
        print("--- goto label1 ---")
        print("--- goto label2 ---")
    end
    
    a = a + 1
    if a < 3 then
        goto label -- a 小于 3 的时候跳转到标签 label
    end
    

    输出:

    --- goto label1 ---
    --- goto label2 ---
    --- goto label1 ---
    --- goto label2 ---
    

    goto 语句经常被用来实现 continue 功能:

    for i = 1, 3 do
        if i  {...} 表示一个由所有变长参数构成的数组
            s = s + v
        end
        return s
    end
    
    print(add(3, 4, 5, 6, 7)) --> 25
    

    我们可以将可变参数赋值给一个变量,#argselect("#", ...)select(n, ...) 三种方式都可以获取可变参数的数量:

    local function average(...)
        local result = 0
        local arg = { ... } --> arg 为一个表,局部变量
        for i, v in ipairs(arg) do
            result = result + v
        end
        print(#arg) --> 6
        print(select("#", ...)) --> 6
        -- 用于返回从起点 n 开始到结束位置的所有参数列表
        print(select(3, ...)) --> 3       4       5       6
        return result / #arg
    end
    
    print(average(10, 5, 3, 4, 5, 6)) --> 5.5
    

    有时候我们可能需要几个固定参数加上可变参数,固定参数必须放在变长参数之前:

    local function fwrite(fmt, ...)  ---> 固定的参数fmt
        return io.write(string.format(fmt, ...))
    end
    
    fwrite("abcdefgn")    -->fmt = "abcdefg", 没有变长参数。  
    fwrite("%d%dn", 1, 2) -->fmt = "%d%d", 变长参数为 1 和 2
    

    内置函数

    Lua 也有很多内置函数,我们可以通过官方手册进行查询:Lua 5.4 Reference Manual - contents

    我这里是用的 5.4 版本的:

    www.lua.org_manual_5.4_.png

    迭代器

    迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。在 Lua 中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。

    在泛型 for 循环中就用到了迭代器,ipairs 就是 Lua 默认提供的迭代函数。

    下面是一个实例:

    local array = { "Google", "Runoob" }
    
    for key, value in ipairs(array)
    do
        print(key, value)
    end
    

    输出:

    1  Google
    2  Runoob
    

    下面我们来分析一下泛型 for 的执行过程:

  • 初始化,计算 in 后面表达式的值,表达式应该返回泛型 for 需要的三个值:迭代函数、状态常量、控制变量(ipairs(array) 会返回迭代函数、array、0);与多值赋值一样,如果表达式返回的结果个数不足三个会自动用 nil 补足,多出部分会被忽略。
  • 将状态常量和控制变量作为参数调用迭代函数(注意:对于 for 结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
  • 将迭代函数返回的值赋给变量列表。
  • 如果返回的第一个值为 nil 循环结束,否则执行循环体。
  • 回到第二步再次调用迭代函数。
  • Lua 中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。Lua 的迭代器包含以下两种类型:

    • 无状态的迭代器
    • 多状态的迭代器

    无状态的迭代器

    无状态的迭代器是指不保留任何状态的迭代器,因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价。

    每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。

    这种无状态迭代器的典型的简单的例子是 ipairs,它遍历数组的每一个元素((1, t[1], (2, t[2]) ...),元素的索引需要是数值。

    以下实例我们使用了一个简单的函数来实现迭代器,实现 数字 n 的平方:

    local function square(iteratorMaxCount, currentNumber)
        if currentNumber < iteratorMaxCount
        then
            currentNumber = currentNumber + 1
            return currentNumber, currentNumber * currentNumber
        end
    end
    
    -- 3 就是状态常量,0就是控制变量
    for i, n in square, 3, 0
    do
        print(i, n)
    end
    

    输出:

    1       1
    2       4
    3       9
    

    迭代的状态包括被遍历的表(循环过程中不会改变的状态常量)和当前的索引下标(控制变量),ipairs 和迭代函数都很简单,我们在 Lua 中可以这样实现:

    local function iter(a, i)
        i = i + 1
        local v = a[i]
        if v then
            return i, v
        end
    end
    
    function ipairs(a)
        return iter, a, 0
    end
    

    Lua 调用 ipairs(a) 开始循环时,他获取三个值:迭代函数 iter、状态常量 a、控制变量初始值 0;然后 Lua 调用 iter(a, 0) 返回 1, a[1](除非 a[1] = nil);第二次迭代调用 iter(a,1) 返回 2, a[2] …… 直到第一个 nil 元素。

    多状态的迭代器

    很多情况下,迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,最简单的方法是使用闭包,还有一种方法就是将所有的状态信息封装到 table 内,将 table 作为迭代器的状态常量,因为这种情况下可以将所有的信息存放在 table 内,所以迭代函数通常不需要第二个参数。

    local array = { "Google", "Runoob" }
    
    local function elementIterator(collection)
        local index = 0
        local count = #collection
        -- 闭包函数
        return function()
            index = index + 1
            if index =5.3)5//2 输出结果 2
    

    关系运算符

    设定 A 的值为10,B 的值为 20

    操作符描述实例
    ==等于,检测两个值是否相等,相等返回 true,否则返回 false(A == B) 为 false。
    ~=不等于,检测两个值是否相等,不相等返回 true,否则返回 false(A ~= B) 为 true。
    大于,如果左边的值大于右边的值,返回 true,否则返回 false(A > B) 为 false。
    =大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false(A >= B) 返回 false。
    3 nil local t2 = setmetatable({ bar = 1 }, { __index = other }) print(t2.foo, t2.bar) --> 3 1
    local mytable = setmetatable({ key1 = "value1" }, {
        __index = function(mytable, key)
            if key == "key2" then
                return "metatablevalue"
            else
                return nil
            end
        end
    })
    print(mytable.key1, mytable.key2) --> value1  metatablevalue
    

    __newindex 元方法

    __newindex 元方法用来对表更新,__index 则用来对表访问 。

    当你给表的一个缺少的索引赋值,解释器就会查找 __newindex 元方法:如果存在则调用这个函数而不进行赋值操作。

    以下实例演示了 __newindex 元方法的应用

    local mymetatable = {}
    local mytable = setmetatable({ key1 = "value1" }, { __newindex = mymetatable })
    
    print(mytable.key1) --> value1
    
    mytable.newkey = "新值2"
    print(mytable.newkey, mymetatable.newkey) --> nil    新值2
    
    mytable.key1 = "新值1"
    print(mytable.key1, mymetatable.key1) --> 新值1    nil
    

    正常情况下,给 newkey 赋值是能正常赋值进去的,但是这里却没有赋值进去,原因就是被 __newindex 拦截了,对已存在的 key1 还是可以正常赋值。

    local mytable = setmetatable({ key1 = "value1" }, {
        __newindex = function(mytable, key, value)
            rawset(mytable, key, """ .. value .. """)
        end
    })
    
    mytable.key1 = "new value"
    mytable.key2 = 4
    
    print(mytable.key1, mytable.key2) --> new value    "4"
    

    操作符相关元方法

    两表相加操作:

    -- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
    -- 自定义计算表中最大键值函数 table_maxn,即返回表最大键值
    local function table_maxn(t)
        local mn = 0
        for k, v in pairs(t) do
            if mn < k then
                mn = k
            end
        end
        return mn
    end
    
    -- 两表相加操作
    local mytable = setmetatable({ 1, 2, 3 }, {
        __add = function(mytable, newtable)
            for i = 1, table_maxn(newtable) do
                table.insert(mytable, table_maxn(mytable) + 1, newtable[i])
            end
            return mytable
        end
    })
    
    local secondtable = { 4, 5, 6 }
    
    mytable = mytable + secondtable
    for k, v in ipairs(mytable) do
        print(k, v)
    end
    

    其它操作符对应的元方法:

    模式 描述
    __add 对应的运算符 '+'.
    __sub 对应的运算符 '-'.
    __mul 对应的运算符 '*'.
    __div 对应的运算符 '/'.
    __mod 对应的运算符 '%'.
    __unm 对应的运算符 '-'.
    __concat 对应的运算符 '..'.
    __eq 对应的运算符 '=='.
    __lt 对应的运算符 '

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论