lua 八种基本类型
数值(number) 内部以double表示
字符串(string) 总是以0结尾,但可以包含任意字符,
布尔(boolean) 只有true和false,只有false和nil 代表失败
函数(function) lua关键概念,并不简单等同于其他语言的函数,
表(table) 异构的hash表,关键概念
userdata 用户定义的c数据结构,脚本用户只能使用,不能定义
线程(thread) lua协作线程(conroutine),与一般的线程不同
nil 代表什么都没有,等同于NULL
函数 example:
function foo(a,b,c,...)
local sum=a+b
return sum,c
end
r1,r2=foo(1,"123","hello")
print(r1,r2)--124 hello
- 函数的定义:
使用关键字function定义,并以关键字end结束 - 局部变量:
使用关键字local定义 ,如果没有local则认为是全局变量 - 函数返回:
可以返回多个值
表example:
local a={}
local b={x=1,["hello"]="world"}
a["astring"]="ni hao"
a[1]=100
a["a table"]=b
for k,v in pairs(a) do
print(k"=>",v)
end
- 定义表:
a={},b={…} - 访问表成员
通过“.”或者“[]” 运算符来访问表的成员
除了nil都可以作为表的键或值,
注:要想删除变量,将其设置为nil即可
一种简单的对象example:
function create(name,id)
local obj={name=name,id=id}
function obj:SetName(name)
self.name=name
end
function obj:GetName()
return self.name
end
function obj:SetId(id)
self.id=id
end
function obj:GetId()
return self.id
end
return obj
end
local mycreate =create("sam",100)
for k,v in pairs(mycreate) do
print(k,"=>",v)
end
print(mycreate:GetName,mycreate.GetId(mycreate))
mycreate:SetId(001)
mycreate:SetName("vane")
print(mycreate:GetName,mycreate.GetId(mycreate))
- 对象的工厂模式
如例子中的create函数, - 用表来表示对象
把对象的所有数据和方法都放进一张表内 - 成员方法的定义
function obj:method(a1,a2,…)…end 等同于 function obj.method(self,a1,a2…)…end
也等价于 obj.method=function(self,a1,a2,…)…end - 成员方法的调用
obj:method(a1,a2,…) 等价与 obj.method(obj,a1,a2,…)
简单的继承
local function CreateRobot(name,id)
local obj ={name=name,id=id}
function obj:SetName(name)
self.name=name
end
function obj:GetName()
return self.name
end
function obj:SetId(id)
self.id=id
end
function obj:GetId()
return self.id
end
return obj
end
local function createFootballRobot(name,id,position)
local obj=CreateRobot(name,id)
obj.position=position
function obj:SetPosition(p)
self.position=p
end
function obj:GetPosition()
return self.position
end
return obj
end
local mycreatefootballrobot=createFootballRobot("tom",1000,"广州")
print(mycreatefootballrobot:GetName(),mycreatefootballrobot:GetId(),mycreatefootballrobot:GetPosition())
mycreatefootballrobot:SetName("maidi")
mycreatefootballrobot:SetId(2222)
mycreatefootballrobot.SetPosition("beijing")
函数闭包
example:
function createCountdownTimer(second)
local ms = second*1000 --upvalue
local function countDown()
ms=ms-1
return ms
end
return countDown
end
local timer1=createCountdownTimer(1)
for i =1,3 do
print(timer1())
end
关于闭包
- upvalue
一个函数使用的定义在函数体之外的局部变量称为函数的upvalue。在上面的例子中ms就是countDown的upvalue,ms是createCountdownTimer的局部变量。 - 函数闭包
一个函数和它所使用的所有upvalue构成了一个函数闭包 - lua函数闭包与c函数的比较
lua函数闭包使函数具有保持它自己的状态的能力,从这个意义上来说,可以与带静态局部变量的c函数相类比,但又有显著的不同:lua中函数是一种基本数据结构类型,代表一种可执行对象,可以有自己的状态,但是对带静态局部变量的c函数来说,它并不是c的一种数据结构,更不会产生任何对象实例,它只是一个静态地址的符号名称。
基于对象的实现
example:
local function create(name,id)
local data={name=name,id=id}--data为obj.SetName,obj.GetName,obj.SetId,obj.GetId的upvalue
local obj={} --把需要隐藏的成员放在一张表李,把该表作为成员函数的upvalue
function obj.SetName(name)
data.name =name
end
function obj.GetName()
return data.name
end
function obj.SetId(id)
data.id=id
end
function obj.GetId()
return data.id
end
return obj
end
实现方式:把需要隐藏的成员放到一张表里,把该表作为成员函数的upvalue
局限性:基于对象的实现不涉及继承及多太。
元表
example1:
local t={}
local m={a="and",b="li lei",c="han"}
setmetatable(t,{__index=m}) --{__index=m}作为t的元表
for k,v in pairs(t) do
print("有?")
print(k,"=>",v)
end
print("------")
print(t.b,t.a,t.c)
example2:
local function add(t1,t2)
assert(#t1==#t2)--#表示获取长度
local length =#t1
for i=1,length do
t1[i]=t1[i]+t2[i]
end
return t1
end
t1=setmetatable({1,2,3},{__add=add})
t2=setmetatable({10,20,30},{__add=add})
for k,v in pairs(t1) do
print(k,"=>",v)
end
for k,v in pairs(t2) do
print(k,"=>",v)
end
print("---------两表相加-----------")
t1=t1+t2
for k,v in pairs(t1) do
print(k,"=>",v)
end
元表定义:
元表本身是普通的表,通过特定的方法(setmetatable)设置到某个对象上,进而影响这个对象的行为,一个对象有哪些行为受到元表影响以及这些行为按照何种方式受到影响是受lua语言约束的。比如前面的例子,两个表的加法,如果没有元表,则会报错,但是lua规定元表可以“重载”对象的加法运算符,因此若把定了加法的元表设置到表上,他们就可以进行加法运算了,元表是lua最重要的概念之一
模式 描述
- __add 对应的运算符 ‘+’.
- __sub 对应的运算符 ‘-’.
- __mul 对应的运算符 ‘*’.
- __div 对应的运算符 ‘/’.
- __mod 对应的运算符 ‘%’.
- __unm 对应的运算符 ‘-’.
- __concat 对应的运算符 ‘…’.
- __eq 对应的运算符 ‘==’.
- __lt 对应的运算符 ‘<’.
- __le 对应的运算符 ‘<=’.
- __index 你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。
- __newindex 当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
- __call 在 Lua 调用一个值时调用
- __tostring 用于修改表的输出行为
基于原型的继承
example:
local Robot={name="sam",id=001}
function Robot:New(extension)
local t=setmetatable(extension or {},self)
self.__index=self
return t
end
function Robot:SetName(name)
self.name=name
end
function Robot:GetName()
return self.name
end
function Robot:SetId(id)
self.id=id
end
function Robot:GetId()
return self.id
end
robot=Robot:new()
print(robot:GetName())
print(robot:GetId())
print("----------------")
local FootballRobot = Robot:New({position="beijing"})
function FootballRobot:SetPosition(p)
self.position=p
end
function FootballRobot:GetPosition()
return self.position
end
fr=FootballRobot:New()
print("fr's position:", fr:GetPosition())
print("fr's name:", fr:GetName())
print("fr's id:", fr:GetId())
print("-----------------")
fr:SetName("Bob")
print("fr's name:", fr:GetName())
print("robot's name:", robot:GetName())
描述:
prototype 模式一个对象既是一个普通的对象,同时可以作为创建其他对象的原型的对象(即类对象),动态的改变原型对象的属性就可以动态的影响所有基于此原型的对象,另外基于一个原型被创建出来的对象可以重载任何属于这个原型对象的方法、属性而不影响原型对象;同时基于原型被创建出来的对象还可以作为原型来创建其他对象。
包
example:
local pack=require "mypack" --导入包(包的名字与定义包的文件名字相同)
print(ver or "no ver defined!")
print(pack.ver)
pack.aFunInMyPack()
print(aFunInMyPack or "no aFunInMyPack define")
aFunInMyPack()
mypacke.lua
module(...,package.seeall) --定义包
ver="0.1 alpha"
function aFunInMyPack()
print("hello")
end
_G.aFunInMyPack=aFunInMyPack
包定义:
包是一种组织代码的方式
实现:
一般一个lua文件内以module函数开始定义一个包,module同时定义一个新的包的函数环境,以使在此包中定义的全局变量都在这个环境中,而非使用包的环境中,
例如:module(…,package.seeall)的意思是定义一个包,包的名字与定义包的文件的名字相同,并且包的函数环境李可以访问使用包的函数环境(比如,包里使用了print,这个变量没有在包里定义,而是定义在使用包的外部环境中)
使用方式:
一般用require函数来导入一个包,要导入的包必须被置于包路径上,包路径可以使用package.path或者环境变量来设定,一般当前工作路径总是在包路径中。
迭代
example:
local function enum(array)
local index=1
return function()
local ret=array[index]
index=index+1
return ret
end
end
local function foreach(array,action)
for element in enum(array) do
action(element)
end
end
foreach({1,2,3},print)
定义:
迭代是for语句的一种特殊形式,可以通过for语句驱动迭代函数对一个给定集合进行遍历。
实现:
enum函数返回一个匿名的迭代函数,for语句每次调用该迭代函数都得到一个值,若该值为nil,则循环结束
协程
local function producer()
return coroutine.create(
function (salt)
local t={1,2,3}
for i =1,#t do
salt = coroutine.yield(t[i]+salt)
end
end)
end
function consumer(prod)
local salt=10
while true do
local running,product=coroutine.resume(prob,salt)
salt=salt*salt
if running then
print(product or "END")
else
break
end
end
end
consumer(producer())
创建协程:
通过coroutine.create可以创建一个协程,该函数接收一个函数类型的参数作为协程运行体,返回一个线程对象
启动线程:
通过coroutine.resume可以启动一个协程或继续一个挂起的协程,该函数接收一个线程对象以及其他需要传递给该线程的参数,线程可以通过线程函数或者coroutine.yield调用的返回值来获取这些参数,当线程初次执行时,resume传递的参数通过线程函数的参数传递给线程,线程从线程函数开始执行,当线程由挂起转为执行时,resume传递的参数以yield调用返回值的形式传递给线程,线程从yield调用后继续执行。
线程放弃调度:
线程调用coroutine.yield暂停自己的执行,并把执行权返回给启动、继续它的线程,线程还可利用yield返回一些值给后者,这些值以resume调用的返回值的形式返回。
lua 基本函数库
assert(v[,message]):
相当于断言,v:当v为nil或false将出发错误,message:发生错误时返回的消息
collectgarbage(opt[,arg]):
垃圾收集器的通用接口,用于操作垃圾收集器,opt:操作方法标志,“stop”:停止垃圾收集,“restart”:重启垃圾收集器,“collect”:执行一次全垃圾收集循环,“count”:返回房钱lua中使用的内存。“step”:单步执行一个垃圾收集,步长有arg参数size指定,如果需要准确指定步长,需要多次实验以达最优效果,如果步长完成一次收集循环,将返回true。“setpause‘:设置arg/10的值作为暂定收集的时长。”setstepmul“:设置arg/100的值作为步长的增幅。
dofile(filename)
打开并且执行一个lua块,当忽略参数filename时,将执行标准输入设备的内容,返回所有块的返回值,当发生错误时,dofile将错误反射给调用者。
error(message[,level]):
终止正在执行的函数,并返回message作为错误信息。通常Error或附加一些错误位置的信息到message头部,level参数指示获得错误的位置,level=1(默认):为调用error位置(文件+行号)。level=2指出调用error函数的函数,level=0不添加信息
_G:
全局环境表,
getfenv(f):
返回函数f的当前环境表,f可以为函数或者调用栈的级别,级别1为当前的函数,级别0或其他值将返回全局环境_G
getmetatable(object):
返回指定对象的元表,如果没有则返回nil
ipairs(t)
返回三个值,迭代函数、表、0多用于穷举表的键名和键值。
load(func[,chunkname]):
装载一个块中的函数,每次调用func将返回一个连接前一结的字串,在块结尾处将返回nil,当没有发生错误时,将返回一个编译完成的块作为函数,否则返回nil加上错误信息,此函数的环境为全局环境,chunkname用于错误和调试信息。
loadfile([filename]):
与load类似,装载的是文件,或者没有指定filename时装载标准输入的内容
loadstring(string[,chunkname]):
与load类似,但装载的内容是一个字符串
next(table[,index]):
运行程序遍历表中的每一个字段,返回下一个索引和值,table:需要遍历的表,index:要返回的索引的前一索引的号,当index是nil时,将返回第一个索引的值,当索引是最后一个索引或表为空时返回nil
pairs(t):
pcall(f,arg1,…):
在保护模式下调用函数。当调用函数成功返回true,失败返回false加错误信息
rawequal(v1,v2):
检查v1是否等于v2,此函数不会调用任何元表的方法
rawget(table,index)
获取指定索引的值,此函数不会调用任何元表的方法
rawset(table,index,value)
设置指定索引的值
select(index,…)
当index为数字将返回所有大于index的参数,当index为#,将返回参数的总个数
setfenv(f,table)
设置函数f的环境表为table
setmetatable(table,metatable):
设置元表,
tonumber(e[,base])
转换为数字,不能转化时返回nil,base指出参数e当前使用的进制
tostring(e)
将e装换为字符串,会触发元表的__tostring
type(e)
返回类型
unpack(list[,i[,j]])
返回指定表的索引的值,i为起始索引,j为结束索引
_VERSION
返回lua版本
xpcall(f,err)
与pcall类似,在保护模式下调用函数(即发生的错误将不会反射给调用者)
但可指定一个新的错误处理函数句柄
当调用函数成功能返回true,失败时将返回false加err返回的结果
lua常用操作系统库
os.time([table])
按table的内容返回一个时间值(数字),若不带参数则返回当前时间.
print(os.time{year=1970, month=1, day=1,hour=8})
print(os.time{year=1970, month=1, day=1}) --若未定义“时,分,秒”,默认时间为正午(04:00:00)
os.date ([format [, time]])
返回一个按format格式化日期、时间的字串或表
函数date,其实是time函数的一种“反函数”。它将一个表示日期和时间的数值,转换成更高级的表现形式。其第一个参数是一个格式化字符串,描述了要返回的时间形式。第二个参数就是时间的数字表示,默认为当前的时间。
t = os.date("*t", os.time());
for i, v in pairs(t) do
print(i,"->",v);
end
Lua string库
--返回字符串s的长度
local s = "HelloWorld"
print(string.len(s)) -->10
--重复n次字符串s的串
print(string.rep(s,2)) -->HelloWorldHelloWorld
--大写字母转换成小写
print(string.lower(s)) -->helloworld
--小写转换成大写
print(string.upper(s)) -->HELLOWORLD
--截取字符串
local s = "[in brackets]"
print(string.sub(s,2,-1)) -->in brackets]
--将每一个数字转换成字符
print(string.char(97)) -->a
--将每一个字符转换成数字
print(string.byte("abc"))
print(string.byte("abc", 2)) --> 98
print(string.byte("abc", -1)) --> 99
--注:使用负数索引访问字符串的最后一个字符
--对字符串进行格式化输出
PI = 3.14165120
print(string.format("pi = %.4f", PI)) -->pi = 3.1417
--注释:使用和C语言的printf函数几乎一模一样,你完全可以照C语言的printf来使用这个函数.
string.find(字符串查找),string.gsub(全局字符串替换),and string.gfind(全局字符串查找)
string.find
用来在目标串(subject string)内搜索匹配指定的模式的串。函数如果找到匹配的串返回他的位置,否则返回nil.最简单的模式就是一个单词,仅仅匹配单词本身。比如,模式’hello’仅仅匹配目标串中的"hello"。当查找到模式的时候,函数返回两个值:匹配串开始索引和结束索引。
理解Lua 语言中的点、冒号与self
点号调用
-- 点号定义和点号调用:
girl = {money = 200}
function girl.goToMarket(girl ,someMoney)
girl.money = girl.money - someMoney
end
girl.goToMarket(girl ,100)
print(girl.money)
引用参数self:
-- 参数self指向调用者自身(类似于c++里的this 指向当前类)
girl = {money = 200}
function girl.goToMarket(self ,someMoney)
self.money = self.money - someMoney
end
girl.goToMarket(girl, 100)
print(girl.money)
冒号调用:
-- 冒号定义和冒号调用:
girl = {money = 200}
function girl:goToMarket(someMoney)
self.money = self.money - someMoney
end
girl:goToMarket(100)
print(girl.money)
冒号定义和冒号调用其实跟上面的效果一样,只是把第一个隐藏参数省略了,而该参数self指向调用者自身。
总结:冒号只是起了省略第一个参数self的作用,该self指向调用者本身,并没有其他特殊的地方。