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

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

  • thread

    在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。 线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停


2. Lua 变量

  • 全局变量

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

  • 局部变量

    局部变量的作用于为从生命位置开始到所在语句块结束

    变量的默认值均为 nil

  • 表中的域

  • 赋值语句

    • Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素使用逗号分开,复制语句右边的值会依次赋值给左边的变量
    • x, y = y, x – 交换 x y 的值
    • 当变量的个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略
      a. 变量的个数 > 值的个数    按变量个数补足 nil
      b. 变量的格式 < 值的格式    多余的值会被忽略
    
    • 多值赋值经常用来交换变量,或将函数调用返回给变量
  • 索引

    • t[i]
    • t.i 当索引为字符串类型时的一种简化写法

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

    print("总共传入".. #arg .. "个数")
    return result/#arg
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 迭代器

  • 无状态的迭代器

    无状态迭代器的典型的简单的例子是 ipairs, 他遍历数组的每一个元素

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 操作

    • table.concat(table[,sep[,start[,end]]])
-- 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, 5, 10}

mytable = mytable + secondtable

for k, v in ipairs(mytable) do
    print(k, v)
end

-- 1	1
-- 2	2
-- 3	3
-- 4	4
-- 5	5
-- 6	10
__add +
__sub -
__mul *
__div /
__mod %
__unm -
__concat ..
__eq ==
__lt <
__le <=
  • __call元方法在 Lua 调用一个值时调用。下面演示了计算表中元素的和
-- 定义元方法 __call
mytable = setmetatable({10}, {
    __call = function(mytable, newtable)
        sum = 0
        for i = 1, table_maxn(mytable) do
            sum = sum + mytable[i]
        end

        for i = 1, table_maxn(newtable) do
            sum = sum + newtable[i]
        end

        return sum
    end
})

newtable = {10, 20, 30}
print(mytable(newtable))
-- 70
  • __tostring元方法

__tostring元方法用于修改表的输出行为。

mytable = setmetatable({10, 20, 30}, {
    __tostring = function(mytable)
        sum = 0
        for k, v in pairs(mytable) do
            sum = sum + v
        end
        return "表所有元素的和为" .. sum
    end
})

print(mytable)
-- 表所有元素的和为60

13. Lua 协同程序(coroutine)

详细参考

Lua 协同程序与县城比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。

线程与协同程序区别:一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作运行。在任意指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被需求挂起的时候才会被挂起。协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。

方法 描述
coroutine.create() 创建 coroutine,返回 coroutine,参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用
coroutine.resume() 重启 coroutine, 和 create 配合使用
coroutine.yield() 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
coroutine.status() 查看coroutine的状态注:coroutine的状态有三种:dead,suspend,running,具体什么时候有这样的状态请参考下面的程序
coroutine.wrap() 创建coroutine,返回一个函数,一旦你调用这个函数,就进入coroutine,和create功能重复
coroutine.running() 返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个corouting的线程号

14. Lua文件 I/O

详细参考

Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。

  • 简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。
  • 完全模式(complete model) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法
-- 简单模式
file = io.open("test.lua", "r")

-- 设置默认输入文件为 test.lua
io.input(file)

-- 输出文件第一行
print(io.read())

-- 关闭打开的文件
io.close(file)

-- 以附加的方式打开只写文件
file = io.open("test.lua", "a")

-- 设置默认输出文件为 test.lua
io.output(file)

-- 在文件最后一行添加 Lua 注释
io.write("-- test.lua 文件末尾注释")

-- 关闭打开的文件
io.close(file)
-- 完全模式
-- 以只读方式打开文件
file = io.open("test.lua", "r")

-- 输出文件第一行
print(file:read())

-- 关闭打开的文件
file:close()

-- 以附加的方式打开只写文件
file = io.open("test.lua", "a")

-- 在文件最后一行添加 Lua 注释
file:write("--test")

-- 关闭打开的文件
file:close()

15. Lua 错误处理

  • error 函数
error (message [, level])
level=1[默认] 为调用 error 位置(文件+行号)
level=2: 指出那个调用 error 函数的函数
level=0: 不添加错误位置信息
local a = 2
if a == 2 then
    error('调用错误信息')
end
  • pcall 和 xpcall、debug 函数
if pcall(function_name, ...) then
    -- 没有错误
else
    -- 一些错误
end
function myfunction()
    n = n / nil
end

function myerrorhandler(err)
    print("ERROR: ", err)
end

status = xpcall(myfunction, myerrorhandler)
print(status)
-- ERROR: 	xpcall.lua:2: attempt to perform arithmetic on global 'n' (a nil value)
-- false

16. Lua 面向对象

详细参考

Lua 中的类可以通过 table+ function 模拟出来。

  • 简单的实例
-- Meta class
Rectangle = {area = 0, length = 0, breadth = 0}

-- 派生类的方法 new
function Rectangle:new(o, length, breadth)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.length = length or 0
    self.breadth = breadth or 0
    self.area = length * breadth

    return o
end

-- 派生类的方法 printArea
function Rectangle:printArea()
    print("矩形面积", self.area)
end


-- 创建对象
r = Rectangle:new(nil, 10, 20)

-- 访问属性
print(r.length)

-- 访问方法
r:printArea()

  • Lua 继承
-- Meta class
Shape = {area = 0}
-- 基础类方法 new
function Shape:new (o,side)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  side = side or 0
  self.area = side*side;
  return o
end
-- 基础类方法 printArea
function Shape:printArea ()
  print("面积为 ",self.area)
end

-- 创建对象
myshape = Shape:new(nil,10)
myshape:printArea()

-- Square 继承 Shape
Square = Shape:new()
-- 派生类方法 new
function Square:new (o,side)
  o = o or Shape:new(o,side)
  setmetatable(o, self)
  self.__index = self
  return o
end

-- 派生类方法 printArea
function Square:printArea ()
  print("正方形面积为 ",self.area)
end

-- 创建对象
mysquare = Square:new(nil,10)
mysquare:printArea()

Rectangle = Shape:new()
-- 派生类方法 new
function Rectangle:new (o,length,breadth)
  o = o or Shape:new(o)
  setmetatable(o, self)
  self.__index = self
  self.area = length * breadth
  return o
end

-- 派生类方法 printArea
function Rectangle:printArea ()
  print("矩形面积为 ",self.area)
end

-- 创建对象
myrectangle = Rectangle:new(nil,10,20)
myrectangle:printArea()
-- 面积为 	100
-- 正方形面积为 	100
-- 矩形面积为 	200

17. Lua 数据库访问

详细参考

详细参考

继续阅读关于 的文章



Fork me on GitHub