Lua 入门

370 次浏览次阅读
没有评论

此篇文章所有操作都是基于上一篇安装的 docker 容器内进行操作

案例来自于 菜鸟教程

首先进入容器
安装 vim

apk add vim

Lua 变量

变量就是给一块内存区域赋予一个值。使得程序可以读取和修改相应内存中内容。

变量由字母、数字、下划线组成。必须以字母或下划线开头。

Lua 是大小写敏感的。

变量分为全局变量和局部变量

type variable_list
local a, b = 1, 10  -- 局部变量
c, d = 2, 20        -- 全局变量

如果变量只定义了没有初始化,则静态存储变量被隐士初始化为 nil

-- 变量定义

local a, b

-- 初始化

a = 1
b = 2

print("value of a:", a)
print("value of b:", b)

-- 变量交换
a, b = b, a

print("value of a:", a)
print("value of b:", b)

Lua 字符串

  • 单引号字符串
  • 双引号字符串
  • [[]]之间的字符串
string1 = "lua"
print("string 1 is", string1)

string2 = "php"
print("string 2 is", string2)

string3 = [["go"]]
print("string3 is", string3)

1.string.upper(str)

2.string.lower(str)

3.string.gsub(mainString, findString, replaceString, num)

mainString 为要操作的字符串, findString 为被替换的字符串, replaceString 要替换的字符串, num 替换次数(忽略为全部替换)

> string.gsub("aaaa", "a", "b", 2)
bbaa 2

4.string.find(str, subsets, [init, [end]])

在一个指定的目标字符串 str 中搜索指定的内容 substr,如果找到了一个匹配的子串,就会返回这个子串的起始索引和结束索引,不存在则返回 nil。

> string.find("hello lua", "lua", 1)

5.string.reverse(str)

> string.reverse("lua")
aul

6.string.format(str)

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

7.string.char(str)

将整型数字转成字符并连接

> string.char(100, 98)
db

8.string.bute(str, [, int])

转换字符为整数值(可以指定某个字符,默认第一个字符

> string.byte("ac")
97

9.string.len(str)

> string.len("aaa")
3
  1. string.rep(string, n)

返回字符串 string 的 n 个拷贝

> string.rep("abcd", 2)
abcdabcd
  1. .. 链接两个字符串
> print("blog.caixiaoxin"..".cn")
blog.caixiaoxin.cn
  1. string.gmatch(str, pattern)

返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回 nil。

> for word in string.gmatch("Hello Lua user", "%a+") do print(word) end
Hello
Lua
user
  1. string.match(str, pattern, init)

string.match()只寻找源字串 str 中的第一个配对. 参数 init 可选, 指定搜寻过程的起点, 默认为 1。
在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回 nil

> = string.match("I have 2 questions for you.", "%d+ %a+")
2 questions

> = string.format("%d, %q", string.match("I have 2 questions for you.", "(%d+) (%a+)"))
2, "questions"
-- 字符串截取
-- string.sub(s, i[,j])

local sourcestr = "prefix--runoobgoogletaobao--suffix"
print("\n 原始字符串 ", string.format("%q", sourcestr))

-- 截取部分 从第 4 个到第 15 个
local first_sub = string.sub(sourcestr, 4, 15)
print("\n 第一次截取 ", string.format("%q", first_sub))

-- 取字符串前缀, 第 1 个到第 8 个
local second_sub = string.sub(sourcestr, 1, 8)
print("\n 第二次截取 ", string.format("%q", second_sub))

-- 截取最后 10 个
local third_sub = string.sub(sourcestr, -10)
print("\n 第三次截取 ", string.format("%q", third_sub))

-- 索引越界 输出原始字符串
local fourth_sub = string.sub(sourcestr, -100)
print("\n 第四次截取 ", string.format("%q", fourth_sub))

-- 字符串大小转换
string1 = "Lua"
print(string.upper(string1))
print(string.lower(string1))

-- 替换字符串
string2 = "Lua Tutorial"
newstring = string.gsub(string2, "Tutorial", "Language")
print("The new string is", newstring)

-- 查找于颠倒
string3 = "Lua Tutorial"
print(string.find(string3, "Tutorial"))
reverseString = string.reverse(string3)
print("the new string is", reverseString)

-- 格式化字符串
string4 = "Lua"
string5 = "Tutorial"
number1 = 10
number2 = 20

print(string.format("Basic formatting %s %s", string4, string5))

-- 日期格式化
date = 2; month = 1; year = 2022
print(string.format("Date formatting %02d/%02d/%03d", date, month, year))

-- 浮点数格式化
print(string.format("%.4f", 1/3))

-- 字符与字节表示
-- 第一个字符
print(string.byte("Lua"))
-- 第三个字符
print(string.byte("Lua", 3))
-- 倒数第一个字符
print(string.byte("Lua", -1))
-- 第二个字符
print(string.byte("Lua", 2))
-- 倒数第三个字符
print(string.byte("Lua", -3))

-- 内部 ASCII 值转换为字符
print(string.char(97))

Lua 数组

数组,就是相同数据类型的元素按一定顺序排列的集合,可以是一维数组和多维数组。

-- 一维数组

array = {"Lua", "Tutorial"}

for i=0, 2 do
    print(array[i])
end

array = {}

for i= -2, 2 do
   array[i] = i *2
end

for i = -2,2 do
   print(array[i])
end

-- 多维数组

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

Lua tale

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

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

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

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

-- 初始化表
mytable = {}

-- 指定值
mytable[1]= "Lua"

-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存

1.table.concat(,sep,[,start[,end]])

concat 是 concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定 table 的数组部分从 start 位置到 end 位置的所有元素, 元素间以指定的分隔符 (sep) 隔开。

2.table.insert(table,[pos],value)

在 table 的数组部分指定位置 (pos) 插入值为 value 的一个元素. pos 参数可选, 默认为数组部分末尾.

3.table.maxn(table)

指定 table 中所有正数 key 值中最大的 key 值. 如果不存在 key 值为正数的元素, 则返回 0。(Lua5.2 之后该方法已经不存在了, 本文使用了自定义函数实现)

4.table.remove(table,[pos])

返回 table 数组部分位于 pos 位置的元素. 其后的元素会被前移. pos 参数可选, 默认为 table 长度, 即从最后一个元素删起。

5.table.sort(table,[,comp])

对给定的 table 进行升序排序。

-- table
mytable = {}
print("mytable 的类型是 ", type(mytable))

mytable[1] = "Lua"
mytable["wow"] = " 修改前 "
print("mytable 索引为 1 的元素是 ", mytable[1])

--alternatetable 和 mytable 指同一个 table
alternatetable = mytable

print("alternatetable 索引为 1 的元素是 ", alternatetable[1])
print("mytable 索引为 wow 的元素是 ", alternatetable["wow"])

alternatetable["wow"] = " 修改后 "
print("mytable 索引为 wow 的元素是 ", mytable["wow"])

-- 释放变量
alternatetable = nil
print("alternatetable 是 ", alternatetable)

-- mytable 仍然可以访问
print("mytable 索引为 wow 的元素是 ", mytable["wow"])

mytable = nil
print("mytable 是 ", mytable)

-- 插入和移除
fruits = {"banana", "orange", "apple"}

-- 在末尾插入
table.insert(fruits, "mango")
print(" 索引为 4 的元素为 ", fruits[4])

-- 在索引为 2 的健处插入
table.insert(fruits, 2, "grapes")
print(" 索引为 2 的元素为 ", fruits[2])

print(" 最后一个元素为 ", fruits[5])
table.remove(fruits)
print(" 移除最后一个元素为 ", fruits[5])

-- table 排序
fruits2 = {"banana", "orange", "apple", "greps"}
print(" 排序前 ")
for k, v in ipairs(fruits2) do
    print(k, v)
end

table.sort(fruits2)
print(" 排序后 ")
for k,v in ipairs(fruits2) do
    print(k, v)

end

-- Table 最大值
function table_maxn(t)
    local mn = nil;
    for k, v in pairs(t) do
        if (mn==nil) then
            mn=v
        end
        if mn < v then
            mn = v
        end
    end
    return mn
end

tbl = {[1]=2, [2]=6,[3]=34, [26]=5}
print("tbl 最大值 :", table_maxn(tbl))
print("tbl 长度 : ", #tbl)

Lua table(表)

在 Lua 语言中,表是唯一可以用来创建不同数据类型的数据结构,比如常见的数组和字典都是用表来创建的。Lua 语言中经常到关联数组这种数据类型,它不仅可以用数值作为索引值,除了 nil 以外的字符串同样可以作为其索引。表没有固定的大小,当数据量增加时表会自动增大

1.table.concat (table [, sep [, start [, end]]]):

concat 是 concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定 table 的数组部分从 start 位置到 end 位置的所有元素, 元素间以指定的分隔符 (sep) 隔开。

2.table.insert (table, [pos,] value):

在 table 的数组部分指定位置 (pos) 插入值为 value 的一个元素. pos 参数可选, 默认为数组部分末尾

3.table.maxn (table)

指定 table 中所有正数 key 值中最大的 key 值. 如果不存在 key 值为正数的元素, 则返回 0。(Lua5.2 之后该方法已经不存在了, 本文使用了自定义函数实现)

4.table.remove (table [, pos])

返回 table 数组部分位于 pos 位置的元素. 其后的元素会被前移. pos 参数可选, 默认为 table 长度, 即从最后一个元素删起。

5.table.sort (table [, comp])

对给定的 table 进行升序排序。

-- table
mytable = {}
print("mytable 的类型是 ", type(mytable))

mytable[1] = "Lua"
mytable["wow"] = " 修改前 "
print("mytable 索引为 1 的元素是 ", mytable[1])

--alternatetable 和 mytable 指同一个 table
alternatetable = mytable

print("alternatetable 索引为 1 的元素是 ", alternatetable[1])
print("mytable 索引为 wow 的元素是 ", alternatetable["wow"])

alternatetable["wow"] = " 修改后 "
print("mytable 索引为 wow 的元素是 ", mytable["wow"])

-- 释放变量
alternatetable = nil
print("alternatetable 是 ", alternatetable)

-- mytable 仍然可以访问
print("mytable 索引为 wow 的元素是 ", mytable["wow"])

mytable = nil
print("mytable 是 ", mytable)

-- table 链接

f = {"apple", "orange", "apple"}
print(" 链接后的字符串 ", table.concat(f))

print(" 链接后的字符串 ", table.concat(f, ", "))

print(" 链接后的字符串 ", table.concat(f, ", ", 2, 3))

-- 插入和移除
fruits = {"banana", "orange", "apple"}

-- 在末尾插入
table.insert(fruits, "mango")
print(" 索引为 4 的元素为 ", fruits[4])

-- 在索引为 2 的健处插入
table.insert(fruits, 2, "grapes")
print(" 索引为 2 的元素为 ", fruits[2])

print(" 最后一个元素为 ", fruits[5])
table.remove(fruits)
print(" 移除最后一个元素为 ", fruits[5])

-- table 排序
fruits2 = {"banana", "orange", "apple", "greps"}
print(" 排序前 ")
for k, v in ipairs(fruits2) do
    print(k, v)
end

table.sort(fruits2)
print(" 排序后 ")
for k,v in ipairs(fruits2) do
    print(k, v)

end

-- Table 最大值
function table_maxn(t)
    local mn = nil;
    for k, v in pairs(t) do
        if (mn==nil) then
            mn=v
        end
        if mn < v then
            mn = v
        end
    end
    return mn
end

tbl = {[1]=2, [2]=6,[3]=34, [26]=5}
print("tbl 最大值 :", table_maxn(tbl))
print("tbl 长度 : ", #tbl)

Lua 函数

函数就是对语句和表达式的封装

用途:

  • 完成指定的任务
  • 计算并返回值

函数的定义

optional_function_scope function function_name(argument1, argument2, argument3..., argumentn)
    function_body
    return result_params_comma_separated
end
  • optional_function_scope: 该参数是可选的制定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local
  • function_name: 指定函数名称。
  • argument1, argument2, argument3…, argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
  • function_body: 函数体,函数中需要执行的代码语句块。
  • result_params_comma_separated: 函数返回值,Lua 语言函数可以返回多个值,每个值以逗号隔开。

单返回值

function max(n1, n2)

    if (n1 > n2) then
        result = n1
    else
        result = n2
    end

    return result
end

print(max(10, 5))

函数作为参数

mprint = function(p)
    print(p)
end

function add(n1, n2, functionPrint)
    result = n1 + n2
    functionPrint(result)
end

mprint(10)
add(1, 5, mprint)

多返回值

function maximum(a)
    local mi = 1
    local m = a[mi]
    for i, val in ipairs(a) do
        if val > m then
            mi = i
            m = val
        end
    end
    return m, mi
end

print(maximum({8, 10, 23, 12, 5}))

可变参数

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(10, 5, 5))
  • select("#"…)
function average(...)
    result = 0
    local arg = {...}
    for i, v in ipairs(arg) do
        result = result + v
    end
    print(" 总共传人 ".. select("#", ...) .. " 个数 ")
    return result/select("#",...)
end

print(" 平均值为 ", average(10, 5, 5))
  • 固定参数和可变参数结合使用。固定参数放在可变参数之前
function f(fmt, ...)
    return io.write(string.format(fmt, ...))
end

f("php\n")
f("%d%d\n", 1, 2)
  • 通常在遍历变长参数的时候只需要使用 {…},然而变长参数可能会包含一些 nil,那么就可以用 select 函数来访问变长参数了:select(‘#’, …) 或者 select(n, …)

    • select(‘#’, …) 返回可变参数的长度。
    • select(n, …) 用于返回从起点 n 开始到结束位置的所有参数列表。
  • 调用 select 时,必须传入一个固定实参 selector(选择开关) 和一系列变长参数。如果 selector 为数字 n,那么 select 返回参数列表中从索引 n 开始到结束位置的所有参数列表,否则只能为字符串 #,这样 select 返回变长参数的总数

Lua 模块

模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

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

module = {}

module.constant = " 常量 "

function module.func1()
    io.write(" 这是一个公有函数 ")
end

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

function module.func3()
    func2()
end

return module
require("module")
-- 或者
-- local m = require("module")

print(module.constant)
module.func3()

由上可知,模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。

上面的 func2 声明为程序块的局部变量,即表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用.

Lua 提供了一个名为 require 的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了

或者给加载的模块定义一个别名变量,方便调用

Lua 流程控制

if…else 流程控制语句

condition 为 true 执行 if 中的语句块 为 false 时执行 else 语句块

if(布尔表达式)
then
   --[布尔表达式为 true 时执行该语句块 --]
else
   --[布尔表达式为 false 时执行该语句块 --]
end
a = 100

if (a<20)
then
    print("a 小于 20")
else
    print("a 大于 20")
end

print("a 的值为 :", a)

if…elseif…else 语句

if(布尔表达式 1)
then
   --[在布尔表达式 1 为 true 时执行该语句块 --]

elseif(布尔表达式 2)
then
   --[在布尔表达式 2 为 true 时执行该语句块 --]

elseif(布尔表达式 3)
then
   --[在布尔表达式 3 为 true 时执行该语句块 --]
else 
   --[如果以上布尔表达式都不为 true 则执行该语句块 --]
end
a = 100

if(a == 10)
then
   print("a 的值为 10")
elseif(a == 20)
then  
   print("a 的值为 20")
elseif(a == 30)
then
   print("a 的值为 30")
else
   print(" 没有匹配 a 的值 ")
end
print("a 的真实值为: ", a)

if 嵌套

if(布尔表达式 1)
then
   --[布尔表达式 1 为 true 时执行该语句块 --]
   if(布尔表达式 2)
   then
      --[布尔表达式 2 为 true 时执行该语句块 --]
   end
end
a = 100;
b = 200;

if(a == 100)
then
   if(b == 200)
   then
      print("a 的值为 100 b 的值为 200");
   end
end
print("a 的值为 :", a);
print("b 的值为 :", b);

Lua 循环

while 循环

while(condition)
do
   statements
end
a = 10
while(a < 20)
do
    print("a 的值为:", a)
    a = a + 1
end

for 循环

数值 for 循环

for var=exp1,exp2,exp3 do  
    < 执行体 >  
end  
#!/usr/local/bin/lua  
function f(x)  
    print("function")  
    return x*2  
end  
for i=1,f(5) do print(i)  
end

泛型 for 循环

#!/usr/local/bin/lua  
days = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}  
for i,v in ipairs(days) do  print(v) end  

repeat…until

重复执行循环,直到 指定的条件为真时为止

repeat
   statements
until(condition)
a = 10
repeat
   print("a 的值为:", a)
   a = a + 1
until(a > 15)

循环嵌套

for init,max/min value, increment
do
   for init,max/min value, increment
   do
      statements
   end
   statements
end
while(condition)
do
   while(condition)
   do
      statements
   end
   statements
end
repeat
   statements
   repeat
      statements
   until(condition)
until(condition)
j =2
for i=2,10 do
   for j=2,(i/j) , 2 do
      if(not(i%j))
      then
         break
      end
      if(j > (i/j))then
         print("i 的值为:",i)
      end
   end
end

Lua 迭代器

迭代器是用于遍历集合或容器中元素的一种结构。在 Lua 语言中,集合往往指的是可以用来创建各种数据结构的表。比如,数组就是用表来创建的。

通用迭代器

array = {"Lua", "PHP"}

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

无状态迭代器

function square(iteratorMaxCount,currentNumber)
   if currentNumber<iteratorMaxCount
   then
      currentNumber = currentNumber+1
   return currentNumber, currentNumber*currentNumber
   end
end

function squares(iteratorMaxCount)
   return square,iteratorMaxCount,0
end  

for i,n in squares(3)
do 
    print(i,n)
end

有状态迭代器

array = {"Lua", "GO"}

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 文件 I/O

Lua I/O 库用于读取和处理文件。包括简单模式和完全模式两种

简单模式: 对一个当前输入文件和一个当前输出文件进行操作

完全模式: 使用外部的句柄来实现

打开文件

file = io.open (filename [, mode])

r 只读模式,以只读模式打开。(存在的文件)

w 可写模式,修改已经存在的文件和创建新的文件

a 追加模式, 对于已存的文件允许追加新内容,但不允许修改原有内容,同时也可以创建新文件

r+ 读写模式打开已存的在文件

w+ 如果文件已存在则删除文件中数据;若文件不存在则新建文件。读写模式打开

a+ 以可读的追加模式打开已存在文件,若文件不存在则新建文件

简单模式

file = io.open("test.lua", "r")
io.input(file)

print(io.read())

io.close(file)

file = io.open("test.lua", "a")
io.output(file)
io.write("-- test.lua 文件末尾注释 ")

io.close(file)

io."x" 的参数

n 读取一个数字并返回它。例:file.read("n")

a 从当前位置读取整个文件。例:file.read("*a")

^l 读取下一行,在文件尾 (EOF) 处返回 nil。例:file.read("*l")

number 返回一个指定字符个数的字符串,或在 EOF 时返回 nil。例:file.read(5)

完全模式

file = io.open("test.lua", "r")
print(file:read())

file:close()

file = io.open("test.lua", "a")
file:write("--test")
file:close()

Lua 错误处理

错误处理是必不可少的。在真实的系统中,往往会遇到不可预期的问题。像数据库事务、文件等等,错误处理就很关键。

错误分类

  • 语法错误
  • 运行时错误

语法错误 demo:

for a= 1,10
   print(a)
end

运行时错误 demo:

function add(a,b)
   return a+b
end

add(10)

Assert 函数

local function add(a,b)
   assert(type(a) == "number", "a 不是一个数字 ")
   assert(type(b) == "number", "b 不是一个数字 ")
   return a+b
end
add(10)

error 函数

error (message [, level])

功能:终止正在执行的函数,并返回 message 的内容作为错误信息(error 函数永远都不会返回)

通常情况下,error 会附加一些错误位置的信息到 message 头部。

Level 参数指示获得错误的位置:

  • Level=1[默认]:为调用 error 位置(文件 + 行号)
  • Level=2:指出哪个调用 error 的函数的函数
  • Level=0: 不添加错误位置信息

pcall 与 xpcall

使用 pcall(f,arg1,…) 函数可以使用保护模式调用一个函数。如果函数 f 中发生了错误,它并不会抛出一个错误,而是返回错误的状态。使用的 pcall 函数的方法如下所示

function myfunction ()
   n = n/nil
end

if pcall(myfunction) then
   print("Success")
else
    print("Failure")
end

执行上面的程序,我们可以得到如下的输出结果:

Failure

xpcall(f,err) 函数调用函数 f 同时为其设置了错误处理方法 err,并返回调用函数的状态。任何发生在函数 f 中的错误都不会传播,而是由 xpcall 函数捕获错误并调用错误处理函数 err,传入的参数即是错误对象本身。xpcall 的使用示例如下:

function myfunction ()
   n = n/nil
end

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

status = xpcall(myfunction, myerrorhandler)
print(status)

执行上面的程序,我们可以得到如下的输出结果:

ERROR:  test2.lua:2: attempt to perform arithmetic on global 'n' (a nil value)
false

作为程序开发人员,在程序中正确合理地处理错误是非常重要的。正确地处理错误可以保证发生意外情况不会影响到程序用户的使用。

Lua 调试(debug)

Lua 提供了 debug 库用于提供创建我们自定义调试器的功能

Lua 本身并未有内置的调试器,但很多开发者共享了他们的 Lua 调试器代码

  • debug()

进入一个用户交互模式,运行用户输入的每个字符串。使用简单的命令以及其它调试设置,用户可以检阅全局变量和局部变量,改变变量的值,计算一些表达式,等等。
输入一行仅包含 cont 的字符串将结束这个函数,这样调用者就可以继续向下运行。

  • getfenv(object)

返回对象的环境变量

  • gethook(optional thread)

返回三个表示线程钩子设置的值:当前钩子函数,当前钩子掩码,当前钩子计数

  • getinfo ([thread,] f [, what])

返回关于一个函数信息的表。你可以直接提供该函数,也可以用一个数字 f 表示该函数。数字 f 表示运行在指定线程的调用栈对应层次上的函数:0 层表示当前函数(getinfo 自身);1 层表示调用 getinfo 的函数(除非是尾调用,这种情况不计入栈);等等。如果 f 是一个比活动函数数量还大的数字,getinfo 返回 nil

  • debug.getlocal ([thread,] f, local)

此函数返回在栈的 f 层处函数的索引为 local 的局部变量 的名字和值。这个函数不仅用于访问显式定义的局部变量,也包括形参、临时变量等

  • getmetatable(value)

把给定索引指向的值的元表压入堆栈。如果索引无效,或是这个值没有元表,函数将返回 0 并且不会向栈上压任何东西

  • getregistry()

返回注册表表,这是一个预定义出来的表,可以用来保存任何 C 代码想保存的 Lua 值

  • getupvalue (f, up)

此函数返回函数 f 的第 up 个上值的名字和值。如果该函数没有那个上值,返回 nil。
以 ‘(‘(开括号)打头的变量名表示没有名字的变量(去除了调试信息的代码块)。

  • sethook ([thread,] hook, mask [, count])

将一个函数作为钩子函数设入。字符串 mask 以及数字 count 决定了钩子将在何时调用。掩码是由下列字符组合成的字符串,每个字符有其含义:

  1. c‘: 每当 Lua 调用一个函数时,调用钩子;

  2. r‘: 每当 Lua 从一个函数内返回时,调用钩子;

  3. l‘: 每当 Lua 进入新的一行时,调用钩子。

  4. setlocal ([thread,] level, local, value)

这个函数将 value 赋给 栈上第 level 层函数的第 local 个局部变量。如果没有那个变量,函数返回 nil。如果 level 越界,抛出一个错误。

  • setmetatable (value, table)

将 value 的元表设为 table(可以是 nil)。返回 value。

  • setupvalue (f, up, value)

这个函数将 value 设为函数 f 的第 up 个上值。如果函数没有那个上值,返回 nil 否则,返回该上值的名字。

  • traceback ([thread,] [message [, level]])

如果 message 有,且不是字符串或 nil,函数不做任何处理直接返回 message。否则,它返回调用栈的栈回溯信息。字符串可选项 message 被添加在栈回溯信息的开头。数字可选项 level 指明从栈的哪一层开始回溯(默认为 1,即调用 traceback 的那里)

function my()
print(debug.traceback("Stack trace"))
print(debug.getinfo(1))
print("Stack trace end")
    return 10
end

my()
print(debug.getinfo(1))

我们经常需要调试函数的内的局部变量。我们可以使用 setupvalue 函数来设置这些局部变量

function newCounter ()
    local n = 0
    local k = 0
    return function ()
        k = n
        n = n + 1
        return n
        end
end

counter = newCounter ()
print(counter())
print(counter())

local i = 1

repeat
    name, val = debug.getupvalue(counter, 1)
    if name then
        print("index", i, name, "=", val)
        if (name == "n") then
            debug.setupvalue(counter, 2, 10)
        end
    i = i + 1
    end -- if
until not name

print(counter())

Lua 面向对象

LUA 中最基本的结构是 table,所以需要用 table 来描述对象的属性

-- 元类
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()
-- 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: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(

Lua 数据库访问

LuaSQL

LuaSQL 可以使用 LuaRocks 来安装可以根据需要安装你需要的数据库驱动

安装 LuaRocks

$ wget http://luarocks.org/releases/luarocks-2.2.1.tar.gz
$ tar zxpf luarocks-2.2.1.tar.gz
$ cd luarocks-2.2.1
$ ./configure; sudo make bootstrap
$ sudo luarocks install luasocket
$ lua
Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
> require "socket"
luarocks install luasql-mysql

Lua 连接 MySql 数据库

require "luasql.mysql"

env = luasql.mysql()

conn = env:connect(" 数据库名 "," 用户名 "," 密码 ","IP 地址 ", 端口)

conn:execute"SET NAMES UTF8"

cur = conn:execute("select * from test")

row = cur:fetch({},"a")

file = io.open("role.txt","w+");

while row do
    var = string.format("%d %s\n", row.id, row.name)

    print(var)

    file:write(var)

    row = cur:fetch(row,"a")
end

file:close()  
conn:close() 
env:close()  

Lua 协同

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

线程和协同程序区别

线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。

在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。

协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同

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

coroutine.resume(co, 1)   -- 1
print(coroutine.status(co))  -- dead

print("----------")

co = coroutine.wrap(function(i)
        print(i);
    end
)

co(1)

print("----------")

co2 = coroutine.create(function()
        for i=1,10 do
            print(i)
            if i == 3 then
                print(coroutine.status(co2))  --running
                print(coroutine.running()) --thread:XXXXXX
            end
            coroutine.yield()
        end
    end
)

coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3

print(coroutine.status(co2))   -- suspended
print(coroutine.running())
function foo (a)
    print("foo 函数输出 ", a)
    return coroutine.yield(2 * a) -- 返回  2*a 的值
end

co = coroutine.create(function (a , b)
    print(" 第一次协同程序执行输出 ", a, b) -- co-body 1 10
    local r = foo(a + 1)

    print(" 第二次协同程序执行输出 ", r)
    local r, s = coroutine.yield(a + b, a - b)  -- a,b 的值为第一次调用协同程序时传入

    print(" 第三次协同程序执行输出 ", r, s)
    return b, " 结束协同程序 "                   -- b 的值为第二次调用协同程序时传入
end)

print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("-- 分割线 ----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("--- 分割线 ---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("--- 分割线 ---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("--- 分割线 ---")
  • 调用 resume,将协同程序唤醒,resume 操作成功返回 true,否则返回 false;
  • 协同程序运行;
  • 运行到 yield 语句;
  • yield 挂起协同程序,第一次 resume 返回;(注意:此处 yield 返回,参数是 resume 的参数)
  • 第二次 resume,再次唤醒协同程序;(注意:此处 resume 的参数中,除了第一个参数,剩下的参数将作为 yield 的参数)
  • yield 返回;
  • 协同程序继续运行;
  • 如果使用的协同程序继续运行完成后继续调用 resume 方法则输出:cannot resume dead coroutine

resume 和 yield 的配合强大之处在于,resume 处于主程中,它将外部状态(数据)传入到协同程序内部;而 yield 则将内部的状态(数据)返回到主程中。

生产者 - 消费者问题

local newProductor

function productor()
     local i = 0
     while true do
          i = i + 1
          send(i)     -- 将生产的物品发送给消费者
     end
end

function consumer()
     while true do
          local i = receive()     -- 从生产者那里得到物品
          print(i)
     end
end

function receive()
     local status, value = coroutine.resume(newProductor)
     return value
end

function send(x)
     coroutine.yield(x)     -- x 表示需要发送的值,值返回以后,就挂起该协同程序
end

-- 启动程序
newProductor = coroutine.create(productor)
consumer()

Lua 垃圾回收

Lua 采用了自动内存管理。这意味着你不用操心新创建的对象需要的内存如何分配出来,也不用考虑在对象不再被使用后怎样释放它们所占用的内存。

Lua 运行了一个 垃圾收集器 来收集所有 死对象(即在 Lua 中不可能再访问到的对象)来完成自动内存管理的工作。Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、内部结构等,都服从自动管理。

Lua 实现了一个增量标记 - 扫描收集器。它使用这两个数字来控制垃圾收集循环:垃圾收集器间歇率和垃圾收集器步进倍率。这两个数字都使用百分数为单位(例如:值 100 在内部表示 1)。

垃圾收集器间歇率控制着收集器需要在开启新的循环前要等待多久。增大这个值会减少收集器的积极性。当这个值比 100 小的时候,收集器在开启新的循环前不会有等待。设置这个值为 200 就会让收集器等到总内存使用量达到 之前的两倍时才开始新的循环。

垃圾收集器步进倍率控制着收集器运作速度相对于内存分配速度的倍率。增大这个值不仅会让收集器更加积极,还会增加每个增量步骤的长度。不要把这个值设得小于 100,那样的话收集器就工作的太慢了以至于永远都干不完一个循环。默认值是 200,这表示收集器以内存分配的 " 两倍 " 速工作。

如果你把步进倍率设为一个非常大的数字(比你的程序可能用到的字节数还大 10%),收集器的行为就像一个 stop-the-world 收集器。接着你若把间歇率设为 200,收集器的行为就和过去的 Lua 版本一样了:每次 Lua 使用的内存翻倍时,就做一次完整的收集。

垃圾回收器函数

Lua 提供了以下函数 collectgarbage ([opt [, arg]]) 用来控制自动内存管理:

  • collectgarbage("collect"): 做一次完整的垃圾收集循环。通过参数 opt 它提供了一组不同的功能:
  • collectgarbage("count"): 以 K 字节数为单位返回 Lua 使用的总内存数。这个值有小数部分,所以只需要乘上 1024 就能得到 Lua 使用的准确字节数(除非溢出)。
  • collectgarbage("restart"): 重启垃圾收集器的自动运行。
  • collectgarbage("setpause"): 将 arg 设为收集器的 间歇率。返回 间歇率 的前一个值。
  • collectgarbage("setstepmul"): 返回 步进倍率 的前一个值。
  • collectgarbage("step"): 单步运行垃圾收集器。步长 " 大小 " 由 arg 控制。传入 0 时,收集器步进(不可分割的)一步。传入非 0 值,收集器收集相当于 Lua 分配这些多(K 字节)内存的工作。如果收集器结束一个循环将返回 true。
  • collectgarbage("stop"): 停止垃圾收集器的运行。在调用重启前,收集器只会因显式的调用运行。
mytable = {"apple", "orange", "banana"}

print(collectgarbage("count"))

mytable = nil

print(collectgarbage("count"))

print(collectgarbage("collect"))

print(collectgarbage("count"))
正文完
 0
评论(没有评论)