Lua学习笔记

1.Lua 交互式编程 and 脚本式编程
2.注释
单行:--
多行:--[[ --]] 多行推荐使用: --[=[ ]=]
3.变量
变量默认是全局的且不需要声明,直接使用不会报错(为nil);删除变量可赋值为nil
4.Lua 中有 8 个基本类型分别为:
nil、boolean、number、string、table 、function、userdata、thread
nil :类型表示一种没有任何有效值 ;对于全局变量和 table,nil 还有一个"删除"作用 。
boolean:Lua 把 false 和 nil 看作是"假",其他的都为"真" ;数字0也表示true。
number类型 -- double(双精度)类型 。
String:由一对双引号或单引号来表示 ,"[[]]" 来表示"一块"字符串 。纯数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字 ;字符串连接使用的是: .. ; 使用 # 来计算字符串的长度,放在字符串前面。
Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。 Lua 里表的默认初始索引一般以 1 开始 ;table 的索引使用方括号[]。Lua 也提供了 . 操作 。
userdata :是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型。
在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西

5.变量
Lua 中的变量全是全局变量,那怕是语句块或是函数里,除非用 local 显式声明为局部变量
Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开 。
当变量个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略:
a. 变量个数 > 值的个数 按变量个数补足nil
b. 变量个数 < 值的个数 多余的值会被忽略
应该尽可能的使用局部变量,有两个好处:避免冲突和快
6.流程控制
while ( boolean表达式) do statements end
repeat statements until(boolean表达式)

for
pairs 能迭代所有键值对。
ipairs 可以想象成 int+pairs,只会迭代键为数字的键值对
for 循环中,循环的索引 i 为外部索引(不是全局变量),修改循环语句中的内部索引 i,不会影响循环次数:
数值for:var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的
i=2;
for i=1,10 do
--i = 10 --区别
print("one time,i:"..i)
print(_G.i);--全局变量i
end
print(i) -- nil
泛型for
for k,v in pairs(_G) do
print(k..":"..type(v))
end
任然循环10次,只是i值被修改了(都是10),结束循环再次print是nil
有break没有continue;
if(布尔表达式1)
then
--[ 在布尔表达式 1 为 true 时执行该语句块 --]

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

elseif( 布尔表达式 3)
then
--[ 在布尔表达式 3 为 true 时执行该语句块 --]
else
--[ 如果以上布尔表达式都不为 true 则执行该语句块 --]
end
7.函数
Lua 提供了许多的内建函数 ;可以遍历_G查看
[local] function function_name( argument1, argument2..., argumentn)
function_body
return result_params
end
函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数 ,可变参数放在最后,(local args ={...} ;select("#", ...)返回可变参数个数)
8.运算符
^ :幂运算
~= :不等于
and or not
优先级
^
not - (unary)

  •  /
    
  •  -
    

..
< > <= >= ~= ==
and
or
9.字符串操作
sub:function
upper:function:字符串全部转大写 string.upper(arg)
len:function:计算字符串长度
gfind:function
rep:function string.rep(string, n) 返回string的n个拷贝串
find:function:string.find (str, substr, [init, [end]]) 在目标字符串str中搜索指定的内容substr(第三个参数为索引),返回其具体位置。不存在则返回 nil
match:function:string.match(str, pattern, init) string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1
char:function:string.char(97,98,99,100) 将整型数字转成字符并连接
dump:function
gmatch:function string.gmatch(str, pattern) 返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。
reverse:function:string.reverse(arg) 字符串反转
byte:function string.byte("ABCD",4) 转换字符为整数值(可以指定某个字符,默认第一个字符)
format:function:string.format("the value is:%d",4) 返回类似printf的格式化字符串
gsub:function :string.gsub(mainString,findString,replaceString,num) mainString为要替换的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数(可以忽略,则全部替换)
lower:function :字符串全部转小写 string.lower(arg)
pattern匹配格式(略)

  1. table
    通过table来模拟构造数组、模块(module)、包(package)和对象(Object)
    setn:function
    table.setn(table, nSize)
    设置table中的元素个数
    insert:function
    table.insert (table, [pos,] value):
    在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾
    getn:function
    table.getn(table)
    返回table中元素的个数
    foreachi:function
    table.foreachi(table, function(i, v))
    会期望一个从 1(数字 1)开始的连续整数范围,遍历table中的key和value逐对进行function(i, v)操作
    maxn:function
    table.maxn (table)
    指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0。(Lua5.2之后该方法已经不存在了,本文使用了自定义函数实现)
    foreach:function:遍历表的 k,v;并按照function操作k,v
    table.foreach(table, function(i, v))
    与foreachi不同的是,foreach会对整个表进行迭代
    concat:function
    table.concat (table [, sep [, start [, end]]])
    concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开
    sort:function
    table.sort (table [, comp])
    对给定的table进行升序排序 comp是一个可选的参数, 此参数是一个外部函数, 可以用来自定义sort函数的排序标准
    remove:function
    table.remove (table [, pos])
    返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。
    注意:
    当我们获取 table 的长度的时候无论是使用 # 还是 table.getn 其都会在索引中断的地方停止计数,而导致无法正确取得 table 的长度 。可用以下方法代替
    function table_leng(t)
    local leng=0
    for k, v in pairs(t) do
    leng=leng+1
    end
    return leng;
    end
    11.Lua 模块与C包
    模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
    Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。
    require 函数
    Lua提供了一个名为require的函数用来加载模块;执行 require 后会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量
    加载机制
    require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化 ;
    C包
    Lua在一个叫loadlib的函数内提供了所有的动态连接的功能。这个函数有两个参数:库的绝对路径和初始化函数。所以典型的调用的例子如下:
    local path = "/usr/local/lua/lib/libluasocket.so"
    local f = loadlib(path, "luaopen_socket")
    loadlib 函数加载指定的库并且连接到 Lua,然而它并不打开库(也就是说没有调用初始化函数),反之他返回初始化函数作为 Lua 的一个函数,这样我们就可以直接在Lua中调用他。
    如果加载动态库或者查找初始化函数时出错,loadlib 将返回 nil 和错误信息。我们可以修改前面一段代码,使其检测错误然后调用初始化函数:
    local path = "/usr/local/lua/lib/libluasocket.so"
    -- 或者 path = "C:\windows\luasocket.dll",这是 Window 平台下
    local f = assert(loadlib(path, "luaopen_socket"))
    f() -- 真正打开库
    一般情况下我们期望二进制的发布库包含一个与前面代码段相似的 stub 文件,安装二进制库的时候可以随便放在某个目录,只需要修改 stub 文件对应二进制库的实际路径即可。
    将 stub 文件所在的目录加入到 LUA_PATH,这样设定后就可以使用 require 函数加载 C 库了。

12.Lua 元表(Metatable)
Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法
为表提供一些有用的行为,例如:表之间的算术运算。。。
有两个很重要的函数来处理元表:
setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
getmetatable(table): 返回对象的元表(metatable)。
在表的元表中设置对应的索引和函数

13 协程(协同程序有点类似同步的多线程 )

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的线程号

Eg
-- 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())

print("----------")
返回结果:
1
dead


1

1
2
3
running
thread: 0x7fb801c05868 false
suspended
thread: 0x7fb801c04c88 true


理解:
coroutine在底层实现就是一个线程。
当create一个coroutine的时候就是在新线程中注册了一个事件。
当使用resume触发事件的时候,create的coroutine函数就被执行了,当遇到yield的时候就代表挂起当前线程,等候再次resume触发事件

14 全局变量
所有的全局变量(_G)都是放在一个特定Lua table 的诸个域中,这个特定的table 叫
作environment(环境) table 或者简称为 环境 。每个函数都有对一个环境的
引用, 所以一个函数中可见的所有全局变量都放在这个函数所引用的环境表(environment table)中。当一个函数被创建出来,它会从创建它的函数中继承其环境,你可以调用getfenv 取得其环境。 如果想改变环境,可以调用 setfenv
关联在线程上的环境被称作全局环境(_G)
_ENV 是当前运行的函数的环境
每个被编译的 Lua 代码块都会有一个外部的局部变量叫 _ENV
多数情况下_ENV=_G

chunk语句块
Lua 把一个chunk 当作一个拥有不定参数的匿名函数处理。正是这样,
chunk 内可以定义局部变量,接收参数,并且返回值。

局部变量被更内层的函数中使用的时候, 它被内层函数称作 upvalue

Lua 是一个嵌入式的扩展语言, 所有的 Lua 动作都是从宿主程序的C 代码调用
Lua 库中的一个函数开始的。在 Lua 编译或运行的任何时候发生了错误,控制权都会交还给C , 而 C 可以来做一些恰当的措施。

Lua与C的相互调用 Lua 的C API
也就是宿主程序跟 Lua 通讯用的一组C 函数

Lua 使用一个虚拟栈来和C 传递值。栈上的的每个元素都是一个Lua 值
几乎所有的API调用都是对栈上的值进行操作

在c中调用lua:将lua数据和函数交给C使用
  在调用C API时有几个重要的头文件:
  (1)lua.h:Lua基础函数库,lua_前缀
  (2)lauxlib.h:辅助库,luaL_前缀,利用lua.h实现的更高层的抽象
  (3)lualib.h:为了保持Lua的苗条,所有的标准库以单独的包提供,所以如果你不需要就不会强求你使用它们。头文件lualib.h定义了打开这些库的函数。例如,调用luaopen_io,以创建io table并注册I/O函数(io.read,io.write等等)到Lua环境中。
lua_State* L = lua_open();//定义lua状态机
luaL_openlibs(L); //初始化
读写Lua全局变量的函数(lua_pushXX、lua_toXX)、调用Lua函数的函数(lua_pcall)、运行Lua代码片断的函数、注册C函数(lua_register)然后可以在Lua中被调用的函数,等等。
栈底为1,依次向上加;也可以栈顶为-1,依次向下减
lua_push*:压入栈元素 参数为状态机和压人栈中的数据
  void lua_pushnil (lua_State *L);
  void lua_pushboolean (lua_State *L, int bool);
  void lua_pushnumber (lua_State *L, double n);
  void lua_pushlstring (lua_State *L, const char *s, size_t length);
  void lua_pushstring (lua_State *L, const char s);
lua_to
:从栈中获得值。即使给定的元素类型不正确,调用这些函数也没问题。
  int lua_toboolean (lua_State *L, int index);
  double lua_tonumber (lua_State *L, int index);
  const char * lua_tostring (lua_State *L, int index);
  size_t lua_strlen (lua_State *L, int index):返回字符串的实际长度。
  int lua_checkstack(lua_State *L, int sz):检查栈空间。默认有20个空闲的记录,lua.h中的LUA_MINSTACK宏定义了这个常量。
  int lua_is... (lua_State *L, int index):检查一个元素能否被转换成指定的类型。
  int lua_type (lua_State L, int idx):返回栈中元素的类型;
  const char
lua_typename(lua_State *L, int tp):返回type对应的名字字符串,第二个参数为lua_type返回的类型
  void luaL_checktype (lua_State *L, int arg, int t):返回参数arg是否是类型t,第三个参数为lua_type的取值。
  在lua.h头文件中,每种类型都被定义为一个常量:LUA_TNIL、LUA_TBOOLEAN、LUA_TNUMBER、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA以及LUA_TTHREAD。
  int lua_gettop (lua_State *L):返回栈中元素个数,它也是栈顶元素的索引。
  void lua_settop (lua_State *L, int index):设置栈顶元素的索引,相当于设置栈的大小。如果开始的栈顶高于新的栈顶,顶部的值被丢弃。否则,为了得到指定的大小这个函数压入相应个数的空值(nil)到栈上。lua_settop(L,0):清空堆栈。
  #define lua_pop(L,n) lua_settop(L, -(n)-1):宏定义,弹出n个元素。
  void lua_pushvalue (lua_State *L, int index):压入堆栈上指定索引的一个抟贝到栈顶,等于拷贝index处的元素,然后添加到栈顶。
  void lua_remove (lua_State *L, int index):移除指定索引的元素,并将其上面所有的元素下移来填补这个位置的空白。
  void lua_insert (lua_State *L, int index):移动栈顶元素到指定索引的位置,并将这个索引位置上面的元素全部上移至栈顶被移动留下的空隔。
  void lua_replace (lua_State *L, int index):从栈顶弹出元素值并将其设置到指定索引位置,没有任何移动操作

C调用Lua(lua提供入栈,C使用出栈)
使用API调用函数的方法是很简单的:
首先,将被调用的函数入栈;
第二,依次将所有参数入栈;
第三,使用lua_pcall调用函数;
最后,从栈中获取函数执行返回的结果。
在将结果入栈之前,lua_pcall会将栈内的函数和参数移除。
如果lua_pcall运行时出现错误,lua_pcall会返回一个非0的结果,并将错误信息入栈(依然会先移除栈内函数和参数)
int lua_pcall (lua_State L, int nargs, int nresults, int msgh);
//调用栈顶函数,指定参数个数:nargs,返回结果个数:nresults,和错误函数msgh 错误处理函数 在栈上的索引位置
Lua 调用C(c提供入栈,Lua使用出栈)
lua_State
L = luaL_newstate();
luaL_openlibs(L);

//注册被Lua调用的C函数,参数"add"表示Lua调用时使用的全局函数名,func为被调用的C函数
lua_register(L, "add", func);
luaL_dostring("print(add(1, 2))");//通过add名使用C函数

lua_close(L);

void lua_register (lua_State *L, const char *name, lua_CFunction f);//把 C 函数 f 设到全局变量 name 中

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,674评论 0 38
  • 1.1程序块:Lua执行的每段代码,例如一个源代码文件或者交互模式中输入的一行代码,都称为一个程序块 1.2注释:...
    c_xiaoqiang阅读 2,585评论 0 9
  • lua C api PS:这里是默认我已经学完了lua脚本的基本知识(包括table,元表,函数,基本库, 文件i...
    绿箭ML阅读 3,382评论 0 1
  • 1、loadstring、dofile和loadfile的用法和区别: (1)对loadstring,程序示例如下...
    陈振拥阅读 490评论 0 2
  • 1、编写供lua调用的C函数 编写一个C函数返回一个table,简单示例代码如下: //返回一个tablestat...
    陈振拥阅读 482评论 0 1