Lua语言

8.5k 词

1. 数据类型

数据类型 描述
nil 只有值为 nil 属于该类,表示一个无效值(在条件表达式中相当于 false)
boolean false or true
number 双精度类型的实浮点数
string 双引号或单引号表示
function 由 C 或 Lua 编写的函数
userdata 表示任意存储在变量中的 C 数据结构
thread 表示执行的独立线路,用于执行协同程序
table Lua 中的表其实是一个”关联数据”, 数组的索引可以是数字或字符串
  • nil
  • boolena
  • number
  • string
    • 可以使用两个方括号”[[]]” 来表示一块字符串
    • 字符串链接使用两个点好 ..
    • 计算字符串的长度使用 #
html = [[
    <html>
    <head></head>
    <body>
        <a href="http://domob.cn">Domob</a>
    </body>
    </html>
]]
print(html)

len = "pemako.cn"
print(#len)

  • function
-- function_test.lua
function factoriall(n)
    if n == 0 then
        return 1
    else
        return n * factoriall(n - 1)
    end
end

print(factoriall(5)) – 120

  • table
    • 不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始
local tb1 = {"apple", "pear", "orange"}

for k, v in pairs(tb1) do
print(k " : " v)
end
– 1 : apple
– 2 : pear
– 3 : orange

  • userdata

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

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

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


2. Lua 变量

  • 全局变量

    <p>Lua 中的变量全是全局变量,哪怕是语句块或是函数里,除非用 local 显示声明为局部变量</p>
    
  • 局部变量

    <p>局部变量的作用于为从生命位置开始到所在语句块结束</p>
    
    <p>变量的默认值均为 <code class="highlighter-rouge">nil</code></p>
    
  • 表中的域

  • 赋值语句

    <ul>
      <li>Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素使用逗号分开,复制语句右边的值会依次赋值给左边的变量</li>
      <li><code class="highlighter-rouge">x, y = y, x</code> – 交换 x y 的值</li>
      <li>当变量的个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略</li>
    </ul>
    
    <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  a. 变量的个数 &gt; 值的个数    按变量个数补足 nil
    

    b. 变量的格式 < 值的格式 多余的值会被忽略

<ul>
  <li>多值赋值经常用来交换变量,或将函数调用返回给变量</li>
</ul>
  • 索引

    <ul>
      <li><code class="highlighter-rouge">t[i]</code></li>
      <li><code class="highlighter-rouge">t.i</code> 当索引为字符串类型时的一种简化写法</li>
    </ul>
    
  • 3. Lua 循环

    • while
    • for
    • repeat...until 重复执行循环,知道指定的条件为真时为止
    • 循环嵌套 可以在循环内嵌套一个或多个循环语句(while for do..while)

    4. Lua 流程控制

    if 表达式
    then
        -- 在表达式为 true 时执行的语句
    end
    

    5. Lua 函数

    optional_function_scope function function_name( argument1, argument2..., argumentn)
        function_body
        return result_params_comma_separated
    end
    -- optional_function_scope 默认不写为全局函数 加上 local 为局部函数
    -- Lua 可以返回多个返回值,每个值已逗号隔开
    
    • 可变参数

    可变参数使用三个点(…) 便是函数有可变参数。Lua 将函数的参数放在一个叫 arg 的表中,#arg 便是传入参数的个数

    function average(...)
        result = 0
        local arg = {...}
        for i,v in ipairs(arg) do
            result = result + v
        end
    
    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;总共传入&#34;</span><span class="o">..</span> <span class="o">#</span><span class="n">arg</span> <span class="o">..</span> <span class="s2">&#34;个数&#34;</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">result</span><span class="o">/#</span><span class="n">arg</span>
    

    end

    print("平均值为:", average(1,2,3,4))
    – 总共传入4个数
    – 平均值为: 2.5

    6. Lua 运算符

    • 算术运算符: + - * / % ^
    • 关系运算符:== ~=(不等于) > < >= <=
    • 逻辑运算符:and or not
    • 其它运算符:..(链接两个字符串) #(返回字符串或表的程度)

    7. Lua 字符串

    • 单引号字符串
    • 双引号字符串
    • [[和]]间的字符串
    • 字符串操作
      • string.upper(argument)
      • string.lower(argument)
      • string.gsub(mainString, findString, replaceString, num)
      • string.strfind(str, substr,[init,[end]])
      • string.reverse(arg)
      • string.format(…)
      • string.len(arg)
      • string.rep(string, n)
      • string.char(arg) 和 string.byte(arg[,int])
    string.gsub("aaaaa", "a", "z", 3) -- 把字符串aaaaa 中的 a 替换为z 天幻3次
    string.gsub("aaaaa", "a", "z") -- 把字符串aaaaa 中的 a 替换为z 全部替换
    

    – 在一个指定的目标字符串中搜索指定的内容(第三个参数为索引)
    string.find("Hello Lua user", "Lua", 1) – 7 9 (分别为开始位置和结束位置的索引)

    string.format("the value is:%d", 4) – the value is:4

    string.rep("abcd", 2) – abcdabcd

    – char 将整数数字转换成字符并连接,byte 转换字符为整数值(可以指定某一个字符,默认第一个字符)
    string.char(97,98,99,100) – abcd
    string.byte("ABCD", 4) – 68
    string.byte("ABCD") – 65

    8. Lua 数组

    Lua数组可以为一维数组或多维数组,数组的索引值可以使用整数表示,数组的大小不固定。

    -- 一维数组
    array = {"Lua", "Tutorial"}
    

    for i=1, #array do
    print(array[i])
    end

    –Lua
    –Tutorial

    – 多维数组
    array = {}
    – 初始化数组
    for i = 1, 3 do
    array[i] = {}
    for j = 1, 3 do
    array[i][j] = i*j
    end
    end
    – 遍历数组
    for i=1, 3 do
    for j = 1, 3 do
    print(array[i][j])
    end
    end

    – 1 2 3 2 4 6 3 6 9

    9. Lua 迭代器

    • 无状态的迭代器

      <p>无状态迭代器的典型的简单的例子是 <code class="highlighter-rouge">ipairs</code>, 他遍历数组的每一个元素</p>
      
    t = {"Lua","Python", "PHP", "Java"}
    for k, v in pairs(t) do
        print(k, v)
    end
    
    • 多状态的迭代器
    array = {"Lua", "Tutorial"}
    

    function elementIterator (collection)
    local index = 0
    local count = #collection
    – 闭包函数
    return function ()
    index = index + 1
    if index <= count
    then
    – 返回迭代器的当前元素
    return collection[index]
    end
    end
    end

    for element in elementIterator(array)
    do
    print(element)
    end

    – Lua
    – Tutorial

    10. Lua table

    table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数字、字典等。

    Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。

    Lua table 是不固定大小的,你可以根据自己需要进行扩容。

    Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用”format”来索引table string。

    • Table 操作

      <ul>
        <li>table.concat(table[,sep[,start[,end]]])</li>
      </ul>
      
    -- concat 链接两个 table 和 PHP 中的 implode 函数很类似
    -- table.concat() 函数列出参数中指定 table 的数组部分从 start 位置到 end 位置的所有元素,元素间已指定的分隔符(sep)隔开
    > language = {"Lua", "Python", "PHP", "Java"}
    > print(table.concat(language))
    LuaPythonPHPJava
    > print(table.concat(language, ','))
    Lua,Python,PHP,Java
    > print(table.concat(language, ',', 1, 2))
    Lua,Python
    
    • table.insert(table[,[pos,]value])
    
    -- 在 table 数组部分指定位置(pos)插入值为 value 的元素,默认从末尾插入
    > language = {"Lua", "Python", "PHP", "Java"}
    > table.insert(language, "Golang")
    > print(language[5])
    Golang
    > table.remove(language)
    > print(language[5])
    nil
    > print(language[1])
    Lua
    > table.remove(language,1)
    > print(language[1])
    Python
    
    - table.remove(table[,pos])
    - table.sort(table[,comp])
    

    11. Lua 模块与包

    Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。以下为创建自定义模块 module.lua,文件代码格式如下:

    • 定义模块
    -- 文件名 utils.lua
    -- 定义一个名为 utils 的模块
    

    utils = {}

    – 定义一个常量
    utils.constant = "这是一个常量"

    – 定义一个函数
    function utils.func1()
    io.write("这是一个共有函数!n")
    end

    local function func2()
    print("这是一个私有函数!")
    end

    function utils.fun3()
    func2()
    end

    return utils

    • 加载模块 require
    
    require("utils") -- 或者使用 require "utils"
                     -- 别名导入 local u = require("utils")
    print(utils.constant)
                    -- print(u.constant)  使用别名
    utils.fun3()
    

    12. Lua 元表(Metatable)

    Lua table 无法对两个 table 进行操作,因此 Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。

    对指定的表设置元表

    • setmetatable(table, metatable): 对指定的 table 设置元表(metatable),如果元表中存在__metatable值,setmetatable会失败
    • getmetatable(table): 返回对象的元表(metatable)

    • __index元方法

    当你通过健来访问 table 的时候,如果这个健没有值,那么 Lua 就会寻找该 table 的 metatable(假定有 metatable)中的__index 健。如果__index包含一个表格,Lua 会在表格中查找相应的健。

    Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio
    > other = { foo = 3}
    > t = setmetatable({}, {__index = other})
    > t.foo
    3
    > t.bar
    nil
    

    如果 __index包含一个函数的话,Lua 就会调用那个函数,table 和健会作为参数传递给函数。__index元房费查看表中元素是否存在,如果不存在,返回结果为 nil, 如果存在则由__index返回结果。

    mytable = setmetatable({key1 = "value1"}, {
        __index = function(mytable, key)
            if key == "key2" then
                return "metablevalue"
            else
                return nil
            end
        end
    })
    

    print(mytable.key1, mytable.key2)
    – value1 metablevalue

    – 上面的代码可以简写为
    mytable = setmetatable({key1="value1", {__index = {key2 = "metatablevalue"}} })

    Lua 查找一个元素时的规则

    1. 在表中查找,如果找到,返回该元素,找不到则继续
    2. 判断该表是否有元表,如果没有元表,返回 nil, 有元表则继续
    3. 判断元表有没有 __index 方法,如果__index 方法为 nil,则返回 nil; 如果 __index 方法是一个表,则重复i, ii, iii; 如果 __index 方法是一个函数,则返回该函数的返回值
    • __newindex 元方法

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

    mymetatable = {}
    mytable = setmetatable({key1 = "vlaue1"}, { __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
    

    以上实例中表设置了元方法 __newindex,在对新索引(newkey)赋值时(mytable.newkey = “新值2”),会调用元方法,而不进行赋值。而如果对已存在的索引健(key1),则会进行赋值,而不调用元方法 __newindex。

    • __add方法

    进行两个表相加操作。

    -- 计算表中最大值,table.maxn 在 Lua5.2以上版本中已无法使用
    -- 自定义计算表中最大值函数 table_maxn
    

    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

    – 两表相加操作
    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
    })

    secondtable = {4<span class