lua入门
参考资料:https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/file.html
一.数据类型
可以通过type()函数来确实变量的类型
eg:
print(type("hello world"))
print(type(type))
print(type(true))
print(type(360.0))
print(type(nil))
1.nil(空)
nil 是一种类型,Lua 将 nil 用于表示“无效值”。一个变量在第一次赋值前的默认值是 nil,将 nil 赋予给一个全局变量就等同于删除它。
eg:
local a
print a
a = 100
print(a)
2.boolean(布尔)
布尔类型,可选值 true/false;Lua 中 nil 和 false 为“假”,其它所有值均为“真”。比如 0 和空字符串就是“真”。
eg:
local a = true
local b = 0
local c = nil
local d = false
if a then
print("a")
else
print("not a")
end
if b then
print("b")
else
print("not b")
end
if c then
print("c")
else
print("not c")
end
if d then
print("d")
else
print("not d")
end
3.number(数字)
Number 类型用于表示实数,和 C/C++ 里面的 double 类型很类似。可以使用数学函数 math.floor(向下取整)和 math.ceil(向上取整)进行取整操作。
eg:
local order = 3.0
local score = 98.5
local id = 444
print(math.floor(order))
print(math.ceil(score))
print(id)
4.string(字符串)
在Lua 中有三种方式表示字符串:a.使用一对匹配的单引号;b.使用一对匹配的双引号;c.使用一种长括号(即[[ ]])括起来的方式定义。Lua 的字符串是不可改变的值,不能像在 c 语言中那样直接修改字符串的某个字符,而是根据修改要求来创建一个新的字符串。Lua 也不能通过下标来访问字符串的某个字符。
Lua 字符串一般都会经历一个“内化”(intern)的过程,即两个完全一样的 Lua 字符串在 Lua 虚拟机中只会存储一份。每一个 Lua 字符串在创建时都会插入到 Lua 虚拟机内部的一个全局的哈希表中。 这意味着:
a.创建相同的 Lua 字符串并不会引入新的动态内存分配操作,所以相对便宜(但仍有全局哈希表查询的开销),
b.内容相同的 Lua 字符串不会占用多份存储空间,
c.已经创建好的 Lua 字符串之间进行相等性比较时是 O(1) 时间度的开销,而不是通常见到的 O(n).
eg:
local str1 = 'hello world'
local str2 = "hello world"
local str3 = [["hello\nworld"]]
local str4 = [=["hello\nworld"]=]
print(str1)
print(str2)
print(str3)
print(str4)
5.table(表)
Table 类型实现了一种抽象的“关联数组”。“关联数组” 是一种具有特殊索引方式的数组,索引通常是字符串(string)或者 number 类型,但也可以是除 nil 以外的任意类型的值。在内部实现上,table 通常实现为一个哈希表、一个数组、或者两者的混合。具体的实现为何种形式,动态依赖于具体的 table 的键分布特点。
eg:
local corp = {
web = "www.baidu.com", --索引为字符串,值为字符串
telephone = "12345", --索引为字符串,值为字符串
staff = {"a","b"}, --索引为字符串,值为表
10086, --索引为数字,值为数字
10087, --索引为数字,值为数字
[10] = 10088, --索引为数字,值为数字
["city"] = "Beijing" --索引为字符串,值为字符串
}
print(corp.web)
print(corp["telephone"])
print(corp[2])
print(corp["city"])
print(corp.staff[1])
6.function(函数)
在 Lua 中,函数 也是一种数据类型,函数可以存储在变量中,可以通过参数传递给其他函数,还可以作为其他函数的返回值。
eg:
local function foo()
print("in the function")
local x = 1
local y = 2
return x + y
end
local a = foo --把函数赋给变量
print (a())
二.表达式
1.算术运算符
eg:
print(1+2) --加法
print(3-2) --减法
print(5/10) --除法
print(5.0/10) --除法
print(2^10) --指数
print(4%3) --取模
print(4*3) --乘法
2.关系运算符
eg:
print(1>2) --大于
print(3>=2) --大于等于
print(4<5) --小于
print(4<=3) --小于等于
print(4 == 5) --等于
print(4 ~= 5) --不等于
3.逻辑运算符
eg:
local a = nil
local b = 0
local c = 100
local d = false
print(a and c) --逻辑与
print(b and c) --逻辑与
print(d and b) --逻辑与
print(d and c) --逻辑与
print(a or c) --逻辑或
print(d or d) --逻辑或
print(not a) --逻辑非
print(not d) --逻辑非
print(not c) --逻辑非
4.字符串连接
在 Lua 中连接两个字符串,可以使用操作符“..”(两个点)。如果其任意一个操作数是数字的话,Lua 会将这个数字转换成字符串。注意,连接操作符只会创建一个新字符串,而不会改变原操作数。
由于 Lua 字符串本质上是只读的,因此字符串连接运算符几乎总会创建一个新的(更大的)字符串。这意味着如果有很多这样的连接操作(比如在循环中使用 .. 来拼接最终结果),则性能损耗会非常大。在这种情况下,推荐使用 table 和 table.concat() 来进行很多字符串的拼接.
eg:
print("hello" .. "world")
print(0 .. 1)
三.控制结构
1.if-else
与 C 语言的不同之处是 elseif 是连在一起的,若不 else 与 if 写成 "else if" 则相当于在 else 里嵌套
eg:
x = 10
if x > 0 then
print("x is a positive number")
end
if x > 0 then
print("x is a positive number")
else
print("x is a non-positive number")
end
if x == 10 then
print("x is 10")
elseif x > 0 then
print("x is a positive number")
else
print("x is a non-positive number")
end
2.while
while 型控制结构语法如下,当表达式值为假(即false或nil)时结束循环。也可以使用 break 语言提前跳出循环。没有提供 do-while 型的控制结构,但是提供了功能相当的 repeat。
while 表达式 do
--body
end
eg:
x = 1
sum = 0
while x <10 do
sum = sum + x
if sum > 10 then
break
end
x = x + 1
end
print(sum)
print(x)
3.repeat
Lua 中的 repeat 控制结构类似于其他语言(如:C++语言)中的 do-while,但是控制方式是刚好相反的。简单点说,执行 repeat 循环体后,直到 until 的条件为真时才结束,而其他语言(如:C++语言)的 do-while 则是当条件为假时就结束循环。
repeat 也可以在使用 break 退出。
eg:
x = 10
repeat
x = x +1
print(x)
until x >= 20
4.for
for 语句有两种形式:数字 for(numeric for)和范型 for(generic for
a.数字型
for var = begin, finish, step do
--body
end
eg:
for i = 1, 5 do
print(i)
end
for 需要关注以下几点:
1.var 从 begin 变化到 finish,每次变化都以 step 作为步长递增 var
2.begin、 finish、 step 三个表达式只会在循环开始时执行一次
3.第三个表达式 step 是可选的, 默认为 1
4.控制变量 var 的作用域仅在 for 循环内,需要在外面控制,则需将值赋给一个新的变量
5.循环过程中不要改变控制变量的值,那样会带来不可预知的影响
b.泛型
泛型 for 循环通过一个迭代器(iterator)函数来遍历所有值
eg:
local a = {"a", "b", "c", "d"}
for i, v in ipairs(a) do
print("index:", i, " value:", v)
end
5.break
语句 break 用来终止 while、repeat 和 for 三种循环的执行,并跳出当前循环体, 继续执行当前循环之后的语句。
eg:
sum = 0
i = 1
while true do
sum = sum + i
if sum > 100 then
break
end
i = i + 1
end
print("The result is " .. i)
6.return
return 主要用于从函数中返回结果,或者用于简单的结束一个函数的执行。 一旦执行了 return 语句,该语句之后的所有语句都不会再执行。若要写在函数中间,则只能写在一个显式的语句块内.
为了调试方便,我们可以想在某个函数的中间提前 return,以进行控制流的短路。此时我们可以将 return 放在一个 do ... end 代码块中.
eg:
local function add(x, y)
return x + y
--print("add: I will return the result " .. (x + y))
--因为前面有个return,若不注释该语句,则会报错
end
local function is_positive(x)
if x > 0 then
return x .. " is positive"
else
return x .. " is non-positive"
end
--由于return只出现在前面显式的语句块,所以此语句不注释也不会报错
--,但是不会被执行,此处不会产生输出
print("function end!")
end
local function foo()
print("before")
do return end
print("after") -- 这一行语句永远不会执行到
end
四.函数
函数是一种对语句和表达式进行抽象的主要机制。函数既可以完成某项特定的任务,也可以只做一些计算并返回结果。在第一种情况中,一句函数调用被视为一条语句;而在第二种情况中,则将其视为一句表达式。
由于函数定义本质上就是变量赋值,而变量的定义总是应放置在变量使用之前,所以函数的定义也需要放置在函数调用之前。
a.函数定义
function function_name (arc) -- arc 表示参数列表,函数的参数列表可以为空
-- body
end
由于全局变量一般会污染全局名字空间,同时也有性能损耗(即查询全局环境表的开销),因此我们应当尽量使用“局部函数”,其记法是类似的,只是开头加上 local 修饰符.
local function function_name (arc)
-- body
end
b.函数的参数
在调用函数的时候,若形参个数和实参个数不同时,Lua 会自动调整实参个数。调整规则:若实参个数大于形参个数,从左向右,多余的实参被忽略;若实参个数小于形参个数,从左向右,没有被实参初始化的形参会被初始化为 nil。
1.按值传递
eg:
local function swap(a, b) --定义函数swap,函数内部进行交换两个变量的值
local temp = a
a = b
b = temp
print(a, b)
end
2.变长参数
Lua 还支持变长参数。若形参为 ... ,表示该函数可以接收不同长度的参数。访问参数的时候也要使用 ... 。
eg:
local function func( ... ) -- 形参为 ... ,表示函数采用变长参数
local temp = {...} -- 访问的时候也要使用 ...
local ans = table.concat(temp, " ") -- 使用 table.concat 库函数对数
-- 组内容使用 " " 拼接成字符串。
print(ans)
end
3.具名参数
Lua 还支持通过名称来指定实参,这时候要把所有的实参组织到一个 table 中,并将这个 table 作为唯一的实参传给函数。
eg:
local function change(arg) -- change 函数,改变长方形的长和宽,使其各增长一倍
arg.width = arg.width * 2
arg.height = arg.height * 2
return arg
end
local rectangle = { width = 20, height = 15 }
print("before change:", "width =", rectangle.width,
"height =", rectangle.height)
4.按引用传递
当函数参数是 table 类型时,传递进来的是 实际参数的引用,此时在函数内部对该 table 所做的修改,会直接对调用者所传递的实际参数生效,而无需自己返回结果和让调用者进行赋值。
eg:
local function change(arg) -- change 函数,改变长方形的长和宽,使其各增长一倍
arg.width = arg.width * 2
arg.height = arg.height * 2
return arg
end
local rectangle = { width = 20, height = 15 }
print("before change:", "width =", rectangle.width,
"height =", rectangle.height)
c.函数返回值
Lua 具有一项与众不同的特性,允许函数返回多个值。当函数返回值的个数和接收返回值的变量的个数不一致时,Lua 也会自动调整参数个数。调整规则: 若返回值个数大于接收变量的个数,多余的返回值会被忽略掉; 若返回值个数小于参数个数,从左向右,没有被返回值初始化的变量会被初始化为 nil。
eg:
local function swap(a, b) -- 定义函数 swap,实现两个变量交换值
return b, a -- 按相反顺序返回变量的值
end
local x = 1
local y = 20
x, y = swap(x, y) -- 调用 swap 函数
print(x, y)
local x, y, z = swap(x, y), 2 -- swap 函数的位置不在最后,此时只返回b的值
print(x, y, z)
print((swap(x, y)), 2) --确保只取函数返回值的第一个值,可以使用括号运算符
print(2, (swap(x, y))) --确保只取函数返回值的第一个值,可以使用括号运算符
五.模块
一个 Lua 模块的数据结构是用一个 Lua 值(通常是一个 Lua 表或者 Lua 函数)。一个 Lua 模块代码就是一个会返回这个 Lua 值的代码块。 可以使用内建函数 require() 来加载和缓存模块。简单的说,一个代码模块就是一个程序库,可以通过 require 来加载。模块加载后的结果通过是一个 Lua table,这个表就像是一个命名空间,其内容就是模块中导出的所有东西,比如函数和变量。require 函数会返回 Lua 模块加载后的结果,即用于表示该 Lua 模块的 Lua 值。
eg:
--把下面的代码保存在文件 my.lua 中
local foo={}
local function getname()
return "Lucy"
end
function foo.greeting()
print("hello " .. getname())
end
return foo
--把下面代码保存在文件 main.lua 中,然后执行 main.lua,调用上述模块。
local fp = require("my")
fp.greeting()
六.String 库
Lua 字符串内部用来标识各个组成字节的下标是从 1 开始的,这不同于像 C 和 Perl 这样的编程语言。其用法为:ans = string.upper(s) ,也能写成 ans = s:upper()。为了避免与之前版本不兼容,此处使用前者。
1.string.byte(s [, i [, j ]]) --返回字符 s[i]、s[i + 1]、s[i + 2]、······、s[j] 所对应的 ASCII 码
eg:
print(string.byte("abc", 1, 3))
print(string.byte("abc", 3)) -- 缺少第三个参数,第三个参数默认与第二个相同,此时为 3
print(string.byte("abc")) -- 缺少第二个和第三个参数,此时这两个参数都默认为 1
2.string.char (...) --接收 0 个或更多的整数(整数范围 :0~255),返回这些整数所对应的 ASCII 码字符组成的字符串
eg:
print(string.char(96, 97, 98))
print(string.char()) -- 参数为空,默认是一个0,可以用string.byte(string.char())测试一下
print(string.char(65, 66))
3.string.upper(s) --接收一个字符串s,返回一个把所有小写字母变成大写字母的字符串
eg:
print(string.upper("Hello Lua"))
4.string.lower(s) --接收一个字符串s,返回一个把所有大写字母变成小写字母的字符串。
eg:
print(string.lower("Hello Lua")) --接收一个字符串s,返回一个把所有大写字母变成小写字母的字符串。
5.string.len(s) --接收一个字符串,返回它的长度
eg:
print(string.len("hello lua"))
6.string.find(s, p [, init [, plain]]) --在 s 字符串中第一次匹配 p 字符串。若匹配成功,则返回 p 字符串在 s 字符串中出现的开始位置和结束位置;若匹配失败,则返回 nil。 第三个参数 init 默认为 1,并且可以为负整数,当 init 为负数时,表示从 s 字符串的 string.len(s) + init 索引处开始向后匹配字符串 p 。 第四个参数默认为 false,当其为 true 时,只会把 p 看成一个字符串对待
eg:
local find = string.find
print(find("abc cba", "ab"))
print(find("abc cba", "ab", 2)) -- 从索引为2的位置开始匹配字符串:ab
print(find("abc cba", "ba", -1)) -- 从索引为7的位置开始匹配字符串:ba
print(find("abc cba", "ba", -3)) -- 从索引为6的位置开始匹配字符串:ba
print(find("abc cba", "(%a+)", 1)) -- 从索引为1处匹配最长连续且只含字母的字符串
print(find("abc cba", "(%a+)", 1, true)) --从索引为1的位置开始匹配字符串:(%a+)
7.string.format(formatstring, ...) --按照格式化参数 formatstring,返回后面 ... 内容的格式化版本
eg:
print(string.format("%.4f", 3.1415926)) -- 保留4位小数
print(string.format("%d %x %o", 31, 31, 31))-- 十进制数31转换成不同进制
d = 29; m = 7; y = 2015 -- 一行包含几个语句,用;分开
print(string.format("%s %02d/%02d/%d", "today is:", d, m, y))
8.string.match(s, p [, init]) --在字符串 s 中匹配(模式)字符串 p,若匹配成功,则返回目标字符串中与模式匹配的子串;否则返回 nil。第三个参数 init 默认为 1,并且可以为负整数,当 init 为负数时,表示从 s 字符串的 string.len(s) + init 索引处开始向后匹配字符串 p
eg:
print(string.match("hello lua", "lua"))
print(string.match("lua lua", "lua", 2)) --匹配后面那个lua
print(string.match("lua lua", "hello"))
print(string.match("today is 27/7/2015", "%d+/%d+/%d+"))
9.string.gmatch(s, p) --返回一个迭代器函数,通过这个迭代器函数可以遍历到在字符串s中出现模式串p的所有地方
eg:
t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "(%a+)=(%a+)") do --匹配两个最长连续且只含字母的
t[k] = v --字符串,它们之间用等号连接
end
for k, v in pairs(t) do
print (k,v)
end
10.string.sub(s, i [, j]) --返回字符串 s 中,索引 i 到索引 j 之间的子字符串。当 j 缺省时,默认为 -1,也就是字符串 s 的最后位置。 i 可以为负数。当索引 i 在字符串 s 的位置在索引 j 的后面时,将返回一个空字符串。
eg:
print(string.sub("Hello Lua", 4, 7))
print(string.sub("Hello Lua", 2))
print(string.sub("Hello Lua", 2, 1)) --看到返回什么了吗
print(string.sub("Hello Lua", -3, -1))
11.string.gsub(s, p, r [, n]) --将目标字符串 s 中所有的子串 p 替换成字符串 r。可选参数 n,表示限制替换次数。返回值有两个,第一个是被替换后的字符串,第二个是替换了多少次
eg:
print(string.gsub("Lua Lua Lua", "Lua", "hello"))
print(string.gsub("Lua Lua Lua", "Lua", "hello", 2))
12.string.reverse (s) --接收一个字符串s,返回这个字符串的反转
eg:
print(string.reverse("Hello Lua"))
七.table 库
table 库是由一些辅助函数构成的,这些函数将 table 作为数组来操作。在 Lua 中,数组下标从 1 开始计数。在初始化一个数组的时候,若不显式地用键值对方式赋值,则会默认用数字作为下标,从 1 开始。由于在 Lua 内部实际采用哈希表和数组分别保存键值对、普通值,所以不推荐混合使用这两种赋值方式。
1.table.getn --获取长度
eg:
local tblTest1 = { 1, a = 2, 3 }
print("Test1 " .. table.getn(tblTest1))
local tblTest2 = { 1, nil }
print("Test2 " .. table.getn(tblTest2))
local tblTest3 = { 1, nil, 2 }
print("Test3 " .. table.getn(tblTest3))
local tblTest4 = { 1, nil, 2, nil }
print("Test4 " .. table.getn(tblTest4))
2.table.concat (table [, sep [, i [, j ] ] ]) --对于元素是 string 或者 number 类型的表 table,返回 table[i]..sep..table[i+1] ··· sep..table[j] 连接成的字符串。填充字符串 sep 默认为空白字符串。起始索引位置 i 默认为 1,结束索引位置 j 默认是 table 的长度。如果 i 大于 j,返回一个空字符串
eg:
local a = {1, 3, 5, "hello" }
print(table.concat(a))
print(table.concat(a, "|"))
print(table.concat(a, " ", 4, 2))
print(table.concat(a, " ", 2, 4))
3.table.insert (table, [pos ,] value) --在(数组型)表 table 的 pos 索引位置插入 value,其它元素向后移动到空的地方。pos 的默认值是表的长度加一,即默认是插在表的最后
eg:
local a = {1, 8} --a[1] = 1,a[2] = 8
table.insert(a, 1, 3) --在表索引为1处插入3
print(a[1], a[2], a[3])
table.insert(a, 10) --在表的最后插入10
print(a[1], a[2], a[3], a[4])
4.table.maxn (table) --返回(数组型)表 table 的最大索引编号;如果此表没有正的索引编号,返回 0
eg:
local a = {}
a[-1] = 10
print(table.maxn(a))
a[5] = 10
print(table.maxn(a))
5.table.remove (table [, pos]) --在表 table 中删除索引为 pos(pos 只能是 number 型)的元素,并返回这个被删除的元素,它后面所有元素的索引值都会减一。pos 的默认值是表的长度,即默认是删除表的最后一个元素
eg:
local a = { 1, 2, 3, 4}
print(table.remove(a, 1)) --删除速索引为1的元素
print(a[1], a[2], a[3], a[4])
print(table.remove(a)) --删除最后一个元素
print(a[1], a[2], a[3], a[4])
6.table.sort (table [, comp]) --按照给定的比较函数 comp 给表 table 排序,也就是从 table[1] 到 table[n] ,这里 n 表示 table 的长度。 比较函数有两个参数,如果希望第一个参数排在第二个的前面,就应该返回 true,否则返回 false。 如果比较函数 comp 没有给出,默认从小到大排序
eg:
local function compare(x, y) --从大到小排序
return x > y --如果第一个参数大于第二个就返回true,否则返回false
end
local a = { 1, 7, 3, 4, 25}
table.sort(a) --默认从小到大排序
print(a[1], a[2], a[3], a[4], a[5])
table.sort(a, compare) --使用比较函数进行排序
print(a[1], a[2], a[3], a[4], a[5])
八.数学库
eg:
print(math.pi) --圆周率
print(math.rad(180)) --角度转换成弧度
print(math.deg(math.pi)) --弧度转换成角度
print(math.sin(1))
print(math.cos(math.pi))
print(math.tan(math.pi / 4))
print(math.atan(1))
print(math.asin(0))
print(math.max(-1, 2, 0, 3.6, 9.1))
print(math.min(-1, 2, 0, 3.6, 9.1))
print(math.fmod(10.1, 3))
print(math.sqrt(360))
print(math.exp(1))
print(math.log(10))
print(math.log10(10))
print(math.floor(3.1415))
print(math.ceil(7.998))
九.文件操作
Lua I/O 库提供两种不同的方式处理文件:隐式文件描述,显式文件描述。任何文件的操作,都将阻塞其他并行执行的请求。
1.隐式文件描述
设置一个默认的输入或输出文件,然后在这个文件上进行所有的输入或输出操作。所有的操作函数由 io 表提供。
eg:
file = io.input("test1.txt") -- 使用 io.input() 函数打开文件
repeat
line = io.read() -- 逐行读取内容,文件结束时返回nil
if nil == line then
break
end
print(line)
until (false)
io.close(file) -- 关闭文件
2.显式文件描述
使用 file:XXX() 函数方式进行操作,其中 file 为 io.open() 返回的文件句柄。
eg:
file = io.open("test2.txt", "r") -- 使用 io.open() 函数,以只读模式打开文件
for line in file:lines() do -- 使用 file:lines() 函数逐行读取文件
print(line)
end
file:close()
十.基本函数
1.assert(arg [, message]) -- arg 为false,程序中断; 为true时,正常执行
2.ipairs(table) --迭代数组元素{1,2,3,4}
3.pairs(table) --迭代table元素{x1=1, x2=2, x3=3, x4=4}
lua高阶
一.元表
在lua中,只能设置table的元表。要设置其它类型的元表,必须通过C代码来完成.
mt = {}
mt.__add = function(a, b){
// todo
}
mt.__sub = function(a, b){
// todo
}
mt.__sub = function(a, b){
// todo
}
mt.__mul = function(a, b){
// todo
}
mt.__div = function(a, b){
// todo
}
mt.__pow = function(a, b){
// todo
}
mt.__concat = function(a, b){
// todo
}
mt.__eq = function(a, b){
// todo
}
mt.__lt = function(a, b){
// todo
}
mt.__le = function(a, b){
// todo
}
mt.__sub = function(a, b){
// todo
}
a = {1,2,3}
b = {4,5,6}
setmetatable(a, mt)
setmetatable(b, mt)
a + b -- 运行元表中的__add方法
a - b -- 运行元表中的__sub方法
二.面向对象编程
在Lua中,可以通过使用函数和表来实现面向对象。将函数和相关的数据放置于同一个表中就形成了一个对象。
local Person = {}
function Person:new(name, age)
return setmetatable({name = name, age = age}, {__index = self})
end
function Person:info()
print(self.name, self.age)
end
function Person:sayname()
print('name:', self.name)
end
local p1 = Person:new('zhangsan', 12)
p1:info()
p1:sayname()
local Student = {}
function Student:new(name, age, class)
setmetatable(self, {__index = Person:new(name, age)}) -- 继承父类
return setmetatable({ class = class}, {__index = self})
end
-- 方法重写
function Student:info()
print(self.name, self.age, self.class)
end
local p2 = Student:new('lisi', 6, 'w')
p2:info()
p1:sayname() --调用父类方法
三.协程
function test1()
while true do
local res, v1, v2 = coroutine.resume(co1, 1, 3)
print(v1, v2)
end
end
--创建协程
co1 = coroutine.create(test1)
function test2()
while true do
local res, v1, v2 = coroutine.yield(100, 300ssssssssss)
print(v1, v2)
end
end
--创建协程
co2 = coroutine.create(test2)
--查看状态
coroutine.status(co1)
--调用
coroutine.resume(co1)
四 全局变量(_G)
a= b
for k, v in pairs(_G) do
print(k, v) -- 是可以看到有a的,这是全局变量
end
五.require执行流程
首先,在package.loaded查找modulname
其次,在package.preload查找modelname,如果存在就作为loader,调用loader(L)
然后,在package.path查找lua文件
最后,在package.cpath查找c库,并调用相关的接口
六.module
--mathlib.lua 文件
module(...)
function add(a, b)
return a +b
end
-- test.lua
local lib = require('mathlib')
print(mathlib.add(1,2)) -- 第一种调用方式
print(lib.add(1,2)) -- 第二种调用方式
参考资料:https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/file.html
一.数据类型
可以通过type()函数来确实变量的类型
eg:
print(type("hello world"))
print(type(type))
print(type(true))
print(type(360.0))
print(type(nil))
1.nil(空)
nil 是一种类型,Lua 将 nil 用于表示“无效值”。一个变量在第一次赋值前的默认值是 nil,将 nil 赋予给一个全局变量就等同于删除它。
eg:
local a
print a
a = 100
print(a)
2.boolean(布尔)
布尔类型,可选值 true/false;Lua 中 nil 和 false 为“假”,其它所有值均为“真”。比如 0 和空字符串就是“真”。
eg:
local a = true
local b = 0
local c = nil
local d = false
if a then
print("a")
else
print("not a")
end
if b then
print("b")
else
print("not b")
end
if c then
print("c")
else
print("not c")
end
if d then
print("d")
else
print("not d")
end
3.number(数字)
Number 类型用于表示实数,和 C/C++ 里面的 double 类型很类似。可以使用数学函数 math.floor(向下取整)和 math.ceil(向上取整)进行取整操作。
eg:
local order = 3.0
local score = 98.5
local id = 444
print(math.floor(order))
print(math.ceil(score))
print(id)
4.string(字符串)
在Lua 中有三种方式表示字符串:a.使用一对匹配的单引号;b.使用一对匹配的双引号;c.使用一种长括号(即[[ ]])括起来的方式定义。Lua 的字符串是不可改变的值,不能像在 c 语言中那样直接修改字符串的某个字符,而是根据修改要求来创建一个新的字符串。Lua 也不能通过下标来访问字符串的某个字符。
Lua 字符串一般都会经历一个“内化”(intern)的过程,即两个完全一样的 Lua 字符串在 Lua 虚拟机中只会存储一份。每一个 Lua 字符串在创建时都会插入到 Lua 虚拟机内部的一个全局的哈希表中。 这意味着:
a.创建相同的 Lua 字符串并不会引入新的动态内存分配操作,所以相对便宜(但仍有全局哈希表查询的开销),
b.内容相同的 Lua 字符串不会占用多份存储空间,
c.已经创建好的 Lua 字符串之间进行相等性比较时是 O(1) 时间度的开销,而不是通常见到的 O(n).
eg:
local str1 = 'hello world'
local str2 = "hello world"
local str3 = [["hello\nworld"]]
local str4 = [=["hello\nworld"]=]
print(str1)
print(str2)
print(str3)
print(str4)
5.table(表)
Table 类型实现了一种抽象的“关联数组”。“关联数组” 是一种具有特殊索引方式的数组,索引通常是字符串(string)或者 number 类型,但也可以是除 nil 以外的任意类型的值。在内部实现上,table 通常实现为一个哈希表、一个数组、或者两者的混合。具体的实现为何种形式,动态依赖于具体的 table 的键分布特点。
eg:
local corp = {
web = "www.baidu.com", --索引为字符串,值为字符串
telephone = "12345", --索引为字符串,值为字符串
staff = {"a","b"}, --索引为字符串,值为表
10086, --索引为数字,值为数字
10087, --索引为数字,值为数字
[10] = 10088, --索引为数字,值为数字
["city"] = "Beijing" --索引为字符串,值为字符串
}
print(corp.web)
print(corp["telephone"])
print(corp[2])
print(corp["city"])
print(corp.staff[1])
6.function(函数)
在 Lua 中,函数 也是一种数据类型,函数可以存储在变量中,可以通过参数传递给其他函数,还可以作为其他函数的返回值。
eg:
local function foo()
print("in the function")
local x = 1
local y = 2
return x + y
end
local a = foo --把函数赋给变量
print (a())
二.表达式
1.算术运算符
eg:
print(1+2) --加法
print(3-2) --减法
print(5/10) --除法
print(5.0/10) --除法
print(2^10) --指数
print(4%3) --取模
print(4*3) --乘法
2.关系运算符
eg:
print(1>2) --大于
print(3>=2) --大于等于
print(4<5) --小于
print(4<=3) --小于等于
print(4 == 5) --等于
print(4 ~= 5) --不等于
3.逻辑运算符
eg:
local a = nil
local b = 0
local c = 100
local d = false
print(a and c) --逻辑与
print(b and c) --逻辑与
print(d and b) --逻辑与
print(d and c) --逻辑与
print(a or c) --逻辑或
print(d or d) --逻辑或
print(not a) --逻辑非
print(not d) --逻辑非
print(not c) --逻辑非
4.字符串连接
在 Lua 中连接两个字符串,可以使用操作符“..”(两个点)。如果其任意一个操作数是数字的话,Lua 会将这个数字转换成字符串。注意,连接操作符只会创建一个新字符串,而不会改变原操作数。
由于 Lua 字符串本质上是只读的,因此字符串连接运算符几乎总会创建一个新的(更大的)字符串。这意味着如果有很多这样的连接操作(比如在循环中使用 .. 来拼接最终结果),则性能损耗会非常大。在这种情况下,推荐使用 table 和 table.concat() 来进行很多字符串的拼接.
eg:
print("hello" .. "world")
print(0 .. 1)
三.控制结构
1.if-else
与 C 语言的不同之处是 elseif 是连在一起的,若不 else 与 if 写成 "else if" 则相当于在 else 里嵌套
eg:
x = 10
if x > 0 then
print("x is a positive number")
end
if x > 0 then
print("x is a positive number")
else
print("x is a non-positive number")
end
if x == 10 then
print("x is 10")
elseif x > 0 then
print("x is a positive number")
else
print("x is a non-positive number")
end
2.while
while 型控制结构语法如下,当表达式值为假(即false或nil)时结束循环。也可以使用 break 语言提前跳出循环。没有提供 do-while 型的控制结构,但是提供了功能相当的 repeat。
while 表达式 do
--body
end
eg:
x = 1
sum = 0
while x <10 do
sum = sum + x
if sum > 10 then
break
end
x = x + 1
end
print(sum)
print(x)
3.repeat
Lua 中的 repeat 控制结构类似于其他语言(如:C++语言)中的 do-while,但是控制方式是刚好相反的。简单点说,执行 repeat 循环体后,直到 until 的条件为真时才结束,而其他语言(如:C++语言)的 do-while 则是当条件为假时就结束循环。
repeat 也可以在使用 break 退出。
eg:
x = 10
repeat
x = x +1
print(x)
until x >= 20
4.for
for 语句有两种形式:数字 for(numeric for)和范型 for(generic for
a.数字型
for var = begin, finish, step do
--body
end
eg:
for i = 1, 5 do
print(i)
end
for 需要关注以下几点:
1.var 从 begin 变化到 finish,每次变化都以 step 作为步长递增 var
2.begin、 finish、 step 三个表达式只会在循环开始时执行一次
3.第三个表达式 step 是可选的, 默认为 1
4.控制变量 var 的作用域仅在 for 循环内,需要在外面控制,则需将值赋给一个新的变量
5.循环过程中不要改变控制变量的值,那样会带来不可预知的影响
b.泛型
泛型 for 循环通过一个迭代器(iterator)函数来遍历所有值
eg:
local a = {"a", "b", "c", "d"}
for i, v in ipairs(a) do
print("index:", i, " value:", v)
end
5.break
语句 break 用来终止 while、repeat 和 for 三种循环的执行,并跳出当前循环体, 继续执行当前循环之后的语句。
eg:
sum = 0
i = 1
while true do
sum = sum + i
if sum > 100 then
break
end
i = i + 1
end
print("The result is " .. i)
6.return
return 主要用于从函数中返回结果,或者用于简单的结束一个函数的执行。 一旦执行了 return 语句,该语句之后的所有语句都不会再执行。若要写在函数中间,则只能写在一个显式的语句块内.
为了调试方便,我们可以想在某个函数的中间提前 return,以进行控制流的短路。此时我们可以将 return 放在一个 do ... end 代码块中.
eg:
local function add(x, y)
return x + y
--print("add: I will return the result " .. (x + y))
--因为前面有个return,若不注释该语句,则会报错
end
local function is_positive(x)
if x > 0 then
return x .. " is positive"
else
return x .. " is non-positive"
end
--由于return只出现在前面显式的语句块,所以此语句不注释也不会报错
--,但是不会被执行,此处不会产生输出
print("function end!")
end
local function foo()
print("before")
do return end
print("after") -- 这一行语句永远不会执行到
end
四.函数
函数是一种对语句和表达式进行抽象的主要机制。函数既可以完成某项特定的任务,也可以只做一些计算并返回结果。在第一种情况中,一句函数调用被视为一条语句;而在第二种情况中,则将其视为一句表达式。
由于函数定义本质上就是变量赋值,而变量的定义总是应放置在变量使用之前,所以函数的定义也需要放置在函数调用之前。
a.函数定义
function function_name (arc) -- arc 表示参数列表,函数的参数列表可以为空
-- body
end
由于全局变量一般会污染全局名字空间,同时也有性能损耗(即查询全局环境表的开销),因此我们应当尽量使用“局部函数”,其记法是类似的,只是开头加上 local 修饰符.
local function function_name (arc)
-- body
end
b.函数的参数
在调用函数的时候,若形参个数和实参个数不同时,Lua 会自动调整实参个数。调整规则:若实参个数大于形参个数,从左向右,多余的实参被忽略;若实参个数小于形参个数,从左向右,没有被实参初始化的形参会被初始化为 nil。
1.按值传递
eg:
local function swap(a, b) --定义函数swap,函数内部进行交换两个变量的值
local temp = a
a = b
b = temp
print(a, b)
end
2.变长参数
Lua 还支持变长参数。若形参为 ... ,表示该函数可以接收不同长度的参数。访问参数的时候也要使用 ... 。
eg:
local function func( ... ) -- 形参为 ... ,表示函数采用变长参数
local temp = {...} -- 访问的时候也要使用 ...
local ans = table.concat(temp, " ") -- 使用 table.concat 库函数对数
-- 组内容使用 " " 拼接成字符串。
print(ans)
end
3.具名参数
Lua 还支持通过名称来指定实参,这时候要把所有的实参组织到一个 table 中,并将这个 table 作为唯一的实参传给函数。
eg:
local function change(arg) -- change 函数,改变长方形的长和宽,使其各增长一倍
arg.width = arg.width * 2
arg.height = arg.height * 2
return arg
end
local rectangle = { width = 20, height = 15 }
print("before change:", "width =", rectangle.width,
"height =", rectangle.height)
4.按引用传递
当函数参数是 table 类型时,传递进来的是 实际参数的引用,此时在函数内部对该 table 所做的修改,会直接对调用者所传递的实际参数生效,而无需自己返回结果和让调用者进行赋值。
eg:
local function change(arg) -- change 函数,改变长方形的长和宽,使其各增长一倍
arg.width = arg.width * 2
arg.height = arg.height * 2
return arg
end
local rectangle = { width = 20, height = 15 }
print("before change:", "width =", rectangle.width,
"height =", rectangle.height)
c.函数返回值
Lua 具有一项与众不同的特性,允许函数返回多个值。当函数返回值的个数和接收返回值的变量的个数不一致时,Lua 也会自动调整参数个数。调整规则: 若返回值个数大于接收变量的个数,多余的返回值会被忽略掉; 若返回值个数小于参数个数,从左向右,没有被返回值初始化的变量会被初始化为 nil。
eg:
local function swap(a, b) -- 定义函数 swap,实现两个变量交换值
return b, a -- 按相反顺序返回变量的值
end
local x = 1
local y = 20
x, y = swap(x, y) -- 调用 swap 函数
print(x, y)
local x, y, z = swap(x, y), 2 -- swap 函数的位置不在最后,此时只返回b的值
print(x, y, z)
print((swap(x, y)), 2) --确保只取函数返回值的第一个值,可以使用括号运算符
print(2, (swap(x, y))) --确保只取函数返回值的第一个值,可以使用括号运算符
五.模块
一个 Lua 模块的数据结构是用一个 Lua 值(通常是一个 Lua 表或者 Lua 函数)。一个 Lua 模块代码就是一个会返回这个 Lua 值的代码块。 可以使用内建函数 require() 来加载和缓存模块。简单的说,一个代码模块就是一个程序库,可以通过 require 来加载。模块加载后的结果通过是一个 Lua table,这个表就像是一个命名空间,其内容就是模块中导出的所有东西,比如函数和变量。require 函数会返回 Lua 模块加载后的结果,即用于表示该 Lua 模块的 Lua 值。
eg:
--把下面的代码保存在文件 my.lua 中
local foo={}
local function getname()
return "Lucy"
end
function foo.greeting()
print("hello " .. getname())
end
return foo
--把下面代码保存在文件 main.lua 中,然后执行 main.lua,调用上述模块。
local fp = require("my")
fp.greeting()
六.String 库
Lua 字符串内部用来标识各个组成字节的下标是从 1 开始的,这不同于像 C 和 Perl 这样的编程语言。其用法为:ans = string.upper(s) ,也能写成 ans = s:upper()。为了避免与之前版本不兼容,此处使用前者。
1.string.byte(s [, i [, j ]]) --返回字符 s[i]、s[i + 1]、s[i + 2]、······、s[j] 所对应的 ASCII 码
eg:
print(string.byte("abc", 1, 3))
print(string.byte("abc", 3)) -- 缺少第三个参数,第三个参数默认与第二个相同,此时为 3
print(string.byte("abc")) -- 缺少第二个和第三个参数,此时这两个参数都默认为 1
2.string.char (...) --接收 0 个或更多的整数(整数范围 :0~255),返回这些整数所对应的 ASCII 码字符组成的字符串
eg:
print(string.char(96, 97, 98))
print(string.char()) -- 参数为空,默认是一个0,可以用string.byte(string.char())测试一下
print(string.char(65, 66))
3.string.upper(s) --接收一个字符串s,返回一个把所有小写字母变成大写字母的字符串
eg:
print(string.upper("Hello Lua"))
4.string.lower(s) --接收一个字符串s,返回一个把所有大写字母变成小写字母的字符串。
eg:
print(string.lower("Hello Lua")) --接收一个字符串s,返回一个把所有大写字母变成小写字母的字符串。
5.string.len(s) --接收一个字符串,返回它的长度
eg:
print(string.len("hello lua"))
6.string.find(s, p [, init [, plain]]) --在 s 字符串中第一次匹配 p 字符串。若匹配成功,则返回 p 字符串在 s 字符串中出现的开始位置和结束位置;若匹配失败,则返回 nil。 第三个参数 init 默认为 1,并且可以为负整数,当 init 为负数时,表示从 s 字符串的 string.len(s) + init 索引处开始向后匹配字符串 p 。 第四个参数默认为 false,当其为 true 时,只会把 p 看成一个字符串对待
eg:
local find = string.find
print(find("abc cba", "ab"))
print(find("abc cba", "ab", 2)) -- 从索引为2的位置开始匹配字符串:ab
print(find("abc cba", "ba", -1)) -- 从索引为7的位置开始匹配字符串:ba
print(find("abc cba", "ba", -3)) -- 从索引为6的位置开始匹配字符串:ba
print(find("abc cba", "(%a+)", 1)) -- 从索引为1处匹配最长连续且只含字母的字符串
print(find("abc cba", "(%a+)", 1, true)) --从索引为1的位置开始匹配字符串:(%a+)
7.string.format(formatstring, ...) --按照格式化参数 formatstring,返回后面 ... 内容的格式化版本
eg:
print(string.format("%.4f", 3.1415926)) -- 保留4位小数
print(string.format("%d %x %o", 31, 31, 31))-- 十进制数31转换成不同进制
d = 29; m = 7; y = 2015 -- 一行包含几个语句,用;分开
print(string.format("%s %02d/%02d/%d", "today is:", d, m, y))
8.string.match(s, p [, init]) --在字符串 s 中匹配(模式)字符串 p,若匹配成功,则返回目标字符串中与模式匹配的子串;否则返回 nil。第三个参数 init 默认为 1,并且可以为负整数,当 init 为负数时,表示从 s 字符串的 string.len(s) + init 索引处开始向后匹配字符串 p
eg:
print(string.match("hello lua", "lua"))
print(string.match("lua lua", "lua", 2)) --匹配后面那个lua
print(string.match("lua lua", "hello"))
print(string.match("today is 27/7/2015", "%d+/%d+/%d+"))
9.string.gmatch(s, p) --返回一个迭代器函数,通过这个迭代器函数可以遍历到在字符串s中出现模式串p的所有地方
eg:
t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "(%a+)=(%a+)") do --匹配两个最长连续且只含字母的
t[k] = v --字符串,它们之间用等号连接
end
for k, v in pairs(t) do
print (k,v)
end
10.string.sub(s, i [, j]) --返回字符串 s 中,索引 i 到索引 j 之间的子字符串。当 j 缺省时,默认为 -1,也就是字符串 s 的最后位置。 i 可以为负数。当索引 i 在字符串 s 的位置在索引 j 的后面时,将返回一个空字符串。
eg:
print(string.sub("Hello Lua", 4, 7))
print(string.sub("Hello Lua", 2))
print(string.sub("Hello Lua", 2, 1)) --看到返回什么了吗
print(string.sub("Hello Lua", -3, -1))
11.string.gsub(s, p, r [, n]) --将目标字符串 s 中所有的子串 p 替换成字符串 r。可选参数 n,表示限制替换次数。返回值有两个,第一个是被替换后的字符串,第二个是替换了多少次
eg:
print(string.gsub("Lua Lua Lua", "Lua", "hello"))
print(string.gsub("Lua Lua Lua", "Lua", "hello", 2))
12.string.reverse (s) --接收一个字符串s,返回这个字符串的反转
eg:
print(string.reverse("Hello Lua"))
七.table 库
table 库是由一些辅助函数构成的,这些函数将 table 作为数组来操作。在 Lua 中,数组下标从 1 开始计数。在初始化一个数组的时候,若不显式地用键值对方式赋值,则会默认用数字作为下标,从 1 开始。由于在 Lua 内部实际采用哈希表和数组分别保存键值对、普通值,所以不推荐混合使用这两种赋值方式。
1.table.getn --获取长度
eg:
local tblTest1 = { 1, a = 2, 3 }
print("Test1 " .. table.getn(tblTest1))
local tblTest2 = { 1, nil }
print("Test2 " .. table.getn(tblTest2))
local tblTest3 = { 1, nil, 2 }
print("Test3 " .. table.getn(tblTest3))
local tblTest4 = { 1, nil, 2, nil }
print("Test4 " .. table.getn(tblTest4))
2.table.concat (table [, sep [, i [, j ] ] ]) --对于元素是 string 或者 number 类型的表 table,返回 table[i]..sep..table[i+1] ··· sep..table[j] 连接成的字符串。填充字符串 sep 默认为空白字符串。起始索引位置 i 默认为 1,结束索引位置 j 默认是 table 的长度。如果 i 大于 j,返回一个空字符串
eg:
local a = {1, 3, 5, "hello" }
print(table.concat(a))
print(table.concat(a, "|"))
print(table.concat(a, " ", 4, 2))
print(table.concat(a, " ", 2, 4))
3.table.insert (table, [pos ,] value) --在(数组型)表 table 的 pos 索引位置插入 value,其它元素向后移动到空的地方。pos 的默认值是表的长度加一,即默认是插在表的最后
eg:
local a = {1, 8} --a[1] = 1,a[2] = 8
table.insert(a, 1, 3) --在表索引为1处插入3
print(a[1], a[2], a[3])
table.insert(a, 10) --在表的最后插入10
print(a[1], a[2], a[3], a[4])
4.table.maxn (table) --返回(数组型)表 table 的最大索引编号;如果此表没有正的索引编号,返回 0
eg:
local a = {}
a[-1] = 10
print(table.maxn(a))
a[5] = 10
print(table.maxn(a))
5.table.remove (table [, pos]) --在表 table 中删除索引为 pos(pos 只能是 number 型)的元素,并返回这个被删除的元素,它后面所有元素的索引值都会减一。pos 的默认值是表的长度,即默认是删除表的最后一个元素
eg:
local a = { 1, 2, 3, 4}
print(table.remove(a, 1)) --删除速索引为1的元素
print(a[1], a[2], a[3], a[4])
print(table.remove(a)) --删除最后一个元素
print(a[1], a[2], a[3], a[4])
6.table.sort (table [, comp]) --按照给定的比较函数 comp 给表 table 排序,也就是从 table[1] 到 table[n] ,这里 n 表示 table 的长度。 比较函数有两个参数,如果希望第一个参数排在第二个的前面,就应该返回 true,否则返回 false。 如果比较函数 comp 没有给出,默认从小到大排序
eg:
local function compare(x, y) --从大到小排序
return x > y --如果第一个参数大于第二个就返回true,否则返回false
end
local a = { 1, 7, 3, 4, 25}
table.sort(a) --默认从小到大排序
print(a[1], a[2], a[3], a[4], a[5])
table.sort(a, compare) --使用比较函数进行排序
print(a[1], a[2], a[3], a[4], a[5])
八.数学库
eg:
print(math.pi) --圆周率
print(math.rad(180)) --角度转换成弧度
print(math.deg(math.pi)) --弧度转换成角度
print(math.sin(1))
print(math.cos(math.pi))
print(math.tan(math.pi / 4))
print(math.atan(1))
print(math.asin(0))
print(math.max(-1, 2, 0, 3.6, 9.1))
print(math.min(-1, 2, 0, 3.6, 9.1))
print(math.fmod(10.1, 3))
print(math.sqrt(360))
print(math.exp(1))
print(math.log(10))
print(math.log10(10))
print(math.floor(3.1415))
print(math.ceil(7.998))
九.文件操作
Lua I/O 库提供两种不同的方式处理文件:隐式文件描述,显式文件描述。任何文件的操作,都将阻塞其他并行执行的请求。
1.隐式文件描述
设置一个默认的输入或输出文件,然后在这个文件上进行所有的输入或输出操作。所有的操作函数由 io 表提供。
eg:
file = io.input("test1.txt") -- 使用 io.input() 函数打开文件
repeat
line = io.read() -- 逐行读取内容,文件结束时返回nil
if nil == line then
break
end
print(line)
until (false)
io.close(file) -- 关闭文件
2.显式文件描述
使用 file:XXX() 函数方式进行操作,其中 file 为 io.open() 返回的文件句柄。
eg:
file = io.open("test2.txt", "r") -- 使用 io.open() 函数,以只读模式打开文件
for line in file:lines() do -- 使用 file:lines() 函数逐行读取文件
print(line)
end
file:close()
十.基本函数
1.assert(arg [, message]) -- arg 为false,程序中断; 为true时,正常执行
2.ipairs(table) --迭代数组元素{1,2,3,4}
3.pairs(table) --迭代table元素{x1=1, x2=2, x3=3, x4=4}
lua高阶
一.元表
在lua中,只能设置table的元表。要设置其它类型的元表,必须通过C代码来完成.
mt = {}
mt.__add = function(a, b){
// todo
}
mt.__sub = function(a, b){
// todo
}
mt.__sub = function(a, b){
// todo
}
mt.__mul = function(a, b){
// todo
}
mt.__div = function(a, b){
// todo
}
mt.__pow = function(a, b){
// todo
}
mt.__concat = function(a, b){
// todo
}
mt.__eq = function(a, b){
// todo
}
mt.__lt = function(a, b){
// todo
}
mt.__le = function(a, b){
// todo
}
mt.__sub = function(a, b){
// todo
}
a = {1,2,3}
b = {4,5,6}
setmetatable(a, mt)
setmetatable(b, mt)
a + b -- 运行元表中的__add方法
a - b -- 运行元表中的__sub方法
二.面向对象编程
在Lua中,可以通过使用函数和表来实现面向对象。将函数和相关的数据放置于同一个表中就形成了一个对象。
local Person = {}
function Person:new(name, age)
return setmetatable({name = name, age = age}, {__index = self})
end
function Person:info()
print(self.name, self.age)
end
function Person:sayname()
print('name:', self.name)
end
local p1 = Person:new('zhangsan', 12)
p1:info()
p1:sayname()
local Student = {}
function Student:new(name, age, class)
setmetatable(self, {__index = Person:new(name, age)}) -- 继承父类
return setmetatable({ class = class}, {__index = self})
end
-- 方法重写
function Student:info()
print(self.name, self.age, self.class)
end
local p2 = Student:new('lisi', 6, 'w')
p2:info()
p1:sayname() --调用父类方法
三.协程
function test1()
while true do
local res, v1, v2 = coroutine.resume(co1, 1, 3)
print(v1, v2)
end
end
--创建协程
co1 = coroutine.create(test1)
function test2()
while true do
local res, v1, v2 = coroutine.yield(100, 300ssssssssss)
print(v1, v2)
end
end
--创建协程
co2 = coroutine.create(test2)
--查看状态
coroutine.status(co1)
--调用
coroutine.resume(co1)
四 全局变量(_G)
a= b
for k, v in pairs(_G) do
print(k, v) -- 是可以看到有a的,这是全局变量
end
五.require执行流程
首先,在package.loaded查找modulname
其次,在package.preload查找modelname,如果存在就作为loader,调用loader(L)
然后,在package.path查找lua文件
最后,在package.cpath查找c库,并调用相关的接口
六.module
--mathlib.lua 文件
module(...)
function add(a, b)
return a +b
end
-- test.lua
local lib = require('mathlib')
print(mathlib.add(1,2)) -- 第一种调用方式
print(lib.add(1,2)) -- 第二种调用方式