Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
打印语句
print("Hello SDHK")
注释
--注释
--[[
注释段
--]]
关键词
and | break | do | else |
elseif | end | false | for |
function | if | in | local |
nil | not | or | repeat |
return | then | true | until |
while | goto |
逻辑运算符
下表列出了 Lua 语言中的常用逻辑运算符,设定 A 的值为 true,B 的值为 false:
操作符 | 描述 | 实例 |
---|---|---|
and | 逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。 | (A and B) 为 false。 |
or | 逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。 | (A or B) 为 true。 |
not | 逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。 | not(A and B) 为 true。 |
全局变量
在默认情况下,变量总是认为是全局的。
全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。
想删除一个全局变量,只需要将变量赋值为nil。
局部变量
i1 = 0--全局变量
local i2 = 0;--局部变量
数据类型
print(type("Hello world")) --string
print(type(10.4*3)) --number Lua 默认只有一种 number 类型 -- double(双精度)类型
print(type(print)) --function
print(type(type)) --function
print(type(true)) --boolean
print(type(nil)) --nil
print(type(type(X))) --string ,X为nil
字符串
str = "this is string"
html = [[
一段字符串
]]
print(#"获取字符串长度")
print(str.."字符串连接"..html)
str = "My String"
str2 = string.upper(str)--转换成大写字母
str3= string.lower(str)--转换成小写字母
str4 =string.gsub(str,"S","i")--S转换为i
str5 =string.gsub(str,"S","i",2)--S转换为i,2为替换次数,默认为全部替换
str6 =string.find(str,"ing")--返回所查找到的位置的索引,可以设置起始搜索位置
str7 = string.reverse(str)--翻转字符串
str8 = string.format("加法运算:%02d+%02d=%02d",num1,num2,(num1+num2))--格式化输出
print(str8)
控制语句:
分支
if(a>=b) then --nil会被判断为false
print("a")
else
print("B")
end
循环
--for循环 变量,最大值,每次+1
for i=1,10,1 do
print(i)
end
--for遍历 双返回 --pairs是迭代器
for k,v in pairs(tab2)do
print(k,v)
end
--类似于do while
repeat
print(a)
a=a+1
until(a>11)--满足时退出循环
自定义迭代循环
--自定义迭代函数
--状态变量不会变化,控制变量会一直变化
function square(state,control)
if(control>=state) then
return nil
else
control = control+1
return control,control*control
end
end
for i,j in square,9,0 do
print(i,j)
end
函数
function ceshi001()--可以返回多变量
return 40,50
end
a,b = ceshi001()
print(a,b)
function ceshi002(...)--多参数传参函数
local arg = {...}--三个点代表可变参数
print(arg[1])
print(#arg)--参数个数获取
end
ceshi002(1,2,3)
--匿名函数
fun(321,
function (name)
print(name.."hello")
end
)
table表
在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表
个人理解:表是个很强大的东西,可以是数组,可以是字典,可以是方法,可以是类。个人感觉更接近字典。
字典和数组
tab1 = {} -- 空表 {}构造表达式
tab2 = {key1 = 100 , key2="v2" } --任意类型键值对
tab3={"a1","a2","a3","a4"}--无键值对时,键为数字 从1开始
array1 ={{},{},{}}--二维数组
tab3[1] = 1 --随意改变储存类型
tab3[2] = nil --删除元素
tab3 = nil--删除整个表,相当于释放内存
表的操作
mytable = {"lua","C#","Java","C++","C"}
table.insert(mytable,"JavaScript")--末端插入数据
table.insert(mytable,2,"Boo")--指定位置插入
table.remove(mytable,2)--删除指定位置
print(table.concat(mytable))--拼接字符串
--指定符号拼接
print(table.concat(mytable,"|"))
table.sort(mytable)--这个排字符串会更具ascll码排序
元表
Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。
元方法 | 描述 |
---|---|
__index | 通过键来访问 table 的时候,如果这个键没有值,那么就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。 1.在表中查找,如果找到,返回该元素,找不到则继续 2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。 3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。 |
__newindex | 当给表的一个不存在的键赋值,解释器就会查找__newindex 元方法: 如果存在则调用这个函数而不进行赋值操作。 如果__newindex是个表,则会拿到这个表继续查找键进行赋值,重复上面操作。 |
设置元表
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
mytable = setmetatable({},{})--另一种写法
--设置__index,定义访问不存在的键时调用的委托事件
mymetatable = {
__index = function(tab,key)
if(key>=10) then
return "不存在的键"
end
end
}
--设置__newindex,定义添加新键值对时调用的委托
mymetatable = {
__newindex = function(tab,key,value)
print("要修改的key为:"..key..",把这个值修改为:"..value)
rawset(tab,key,value)--设置一个键值对到表
end
}
--设置__add,可以定义表和表之间的+操作符运算
mymetatable = {
__add = function(tab,newtab)
local m1 = 0
for k,v in pairs(tab) do
if(k>m1) then
m1= k
end
end
for k,v in pairs(newtab) do
m1 = m1+1
table.insert(tab,m1,v)
end
return tab
end
}
--设置__call属性,可以吧表当成函数使用
mymetatable = {
__call = function (tab,arg)
print(arg)
return "SDHK"
end
}
--设置__tostring,可以定义打印表的委托方法
mymetatable = {
__tostring = function(tab)
local str = ""
for k,v in pairs(tab) do
str = str..v.."."
end
return str
end
}
运算符键
模式 | 描述 |
---|---|
__add | 对应的运算符 '+'. |
__sub | 对应的运算符 '-'. |
__mul | 对应的运算符 '*'. |
__div | 对应的运算符 '/'. |
__mod | 对应的运算符 '%'. |
__unm | 对应的运算符 '-'. |
__concat | 对应的运算符 '..'. |
__eq | 对应的运算符 '=='. |
__lt | 对应的运算符 '<'. |
__le | 对应的运算符 '<='. |
引入模块
--模块代码 :文件名"module.Lua"
module ={}
module.var = "siki"
module.func1 = function() --匿名函数赋值给变量
print("这个是module里的函数")
end
local function func2()--局部函数相当于私有函数
print("这个是module的局部函数")
end
function module.func3()--全局变量需要加上表名
print("这个是module的全局函数")
end
return module
--引入lua模块
--require "模块文件名"
m = require "module" --返回的是表
print(module.var)--调用模块
m.func1()--调用表里方法
协同程序
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 的线程号 |
--定义协同函数
co = coroutine.create(
function (a,b)--匿名函数不需要写函数名
print(a+b)
print(coroutine.status(co)) --打印状态:running
--挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
coroutine.yield(a*b)
print(coroutine.status(co)) --running
print(a-b)
return a*b+1
end
)
--启动协同函数
coroutine.resume(co,20,30)
--定义协同函数的第二种方法:这种方法好像有使用限制
co1 = coroutine.wrap(
function (a,b)--匿名函数不需要写函数名
print(a+b)
coroutine.yield(a*b)
print(a-b)
return a*b+2
end
)
co1(20,30)--启动协同函数
res1,res2 = coroutine.resume(co)--再启动协同程序,不需要再次传递参数
print("携程启动成功:",res1,"返回值为",res2)
文件读写
Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。
- 简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。
- 完全模式(complete model) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法
简单模式在做一些简单的文件操作时较为合适。但是在进行一些高级的文件操作的时候,简单模式就显得力不从心。例如同时读取多个文件这样的操作,使用完全模式则较为合适。
模式 | 描述 |
---|---|
r | 以只读方式打开文件,该文件必须存在。 |
w | 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 |
a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留) |
r+ | 以可读写方式打开文件,该文件必须存在。 |
w+ | 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
a+ | 与a类似,但此文件可读可写 |
b | 二进制模式,如果文件是二进制文件,可以加上b |
+ | 号表示对文件既可以读也可以写 |
模式 | 描述 |
---|---|
"*n" | 读取一个数字并返回它。例:file.read("*n") |
"*a" | 从当前位置读取整个文件。例:file.read("*a") |
"*l"(默认) | 读取下一行,在文件尾 (EOF) 处返回 nil。例:file.read("*l") |
number | 返回一个指定字符个数的字符串,或在 EOF 时返回 nil。例:file.read(5) |
file = io.open("data1.txt","r")
-- 设置默认输入文件为 ata1.txt
io.input(file)
print( io.read())--读取一行
print( io.read())--读取下一行 默认*|
print( io.read("*a"))--读取剩下全部字符
io.close()-- 关闭打开的文件
--追加只写a
file = io.open("data1.txt","a")
io.output(file)
--io.write("SD_Y_HK\n")
io.close()
--完全模式
file = io.open("data1.txt","r")
print(file:read())
file:close()
面向对象
- 封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性。
- 继承:继承的方法允许在不改动原程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。这有利于减少重复编码,提高软件的开发效率。
- 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
- 抽象:抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。
LUA中最基本的结构是table,所以需要用table来描述对象的属性。
lua 中的 function 可以用来表示方法。那么LUA中的类可以通过 table + function 模拟出来。
至于继承,可以通过 metetable 模拟出来
定义类
-- 元类 :把这个看为定义类
Rectangle = {area = 0, length = 0, breadth = 0}
-- 派生类的方法 new :定义类的New方法和构造函数
function Rectangle:new (o,length,breadth)
o = o or {} --假如o不为nil则返回自己,为nil则新建表
setmetatable(o, self) --把自己设置为O的原表
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
RT = Rectangle:new(nil,10,20)--新建对象
print(r.length)--属性访问
r:printArea()--函数访问
继承类
-- 基类
Shape = {area = 0}
-- 基础类方法 new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self) --将自己设置为O的元表
self.__index = self --将自己复制一份
side = side or 0
self.area = side*side;
return o
end
-- 基础类方法 printArea
function Shape:printArea ()
print("面积为 ",self.area)
end
Square = Shape:new() --新建复制父类
function Square:new (o,side) --子类的new方法
o = o or Shape:new(o,side) --假如o为nil则复制一个父类为新类
setmetatable(o, self) --将自己设置为新类的元表
self.__index = self --通过不存在事件,将自己复制一份
return o --新建好的子类
end
-- 派生类方法 printArea 重写函数
function Square:printArea ()
print("正方形面积 ",self.area)
end