在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
为什么要学Lua呢,因为大学时玩了一款游戏叫饥荒,最近发现做脚本也要用到这门语言,于是就简单的学习一下,毕竟广大程序员的乐趣就是会敲各种语言的Hello World。 此篇参考链接: http://www.runoob.com/lua/lua-tutorial.html 设计目的其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。这句话言外之意就是“我就是个做脚本的,目的就是为了嵌入到应用程序中辅助扩展”。 Lua 特性
Lua 应用场景
Lua 环境安装Windows环境安装google code下载,这个需要FQ,也可以从其他地方下载。 安装完后是个黑框框,cmd命令模式执行,跟java环境配置调用命令大同小异。这个是用来运行最终文件的。 跟java一样要有IDE,类似于IDEA和myeclipse,这个在安装Lua的过程中会有一个叫SciTE的软件,这个就是Lua的编辑器。 Linux安装环境如果你没有Linux运行环境,仅仅是用Lua这么小的东西,不想安装虚拟机又不想买服务器的话。可以尝试腾讯云的Cloud Studio,在线编辑、运行。 Cloud Studio是基于浏览器的集成式开发环境,支持绝大部分编程语言,包括 HTML5、PHP、Python、Java、Ruby、C/C++、.NET 等等,无需下载安装程序,一键切换开发环境。Cloud Studio提供了完整的 Linux 环境,并且支持自定义域名指向,动态计算资源调整,可以完成各种应用的开发编译与部署。 新建界面时这个样子的,发现上面没有Lua,要去下载Code Runner插件。创建一个无来源的Blank,进入选择运行环境(这里我选择Java),然后安装Lua环境(效果和Windows安装的一样) 在java的linux上安装lua环境 sudo apt-get install libreadline-dev #先安装lua环境需要的lib,不行的话换个环境试试 curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz tar zxf lua-5.3.0.tar.gz cd lua-5.3.0 make linux sudo make install #一定要sudo,不然可能会出现权限不允许的情况,因为你是coding,文件夹是root 写个Hello World,没问题 如果你既不想装windows的环境也不想装linux的环境,仅仅是为了学习或者看Lua基础代码的运行结果,可以用lua官网自带的demo测试代码页面 Lua 基本语法交互式编程输入lua,进入控制台交互界面 脚本式编程直接在cmd中输入lua main.lua,java是需要编译后再用java命令调用class文件,而lua不需要编译可以直接调用 注释单行注释两个减号是单行注释: --
多行注释--[[ 多行注释 多行注释 --]] 标示符Lua 标示符用于定义一个变量,函数获取其他用户定义的项。标示符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后加上0个或多个字母,下划线,数字(0到9)。 最好不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的。Lua 不允许使用特殊字符如 @, $, 和 % 来定义标示符。 Lua 是一个区分大小写的编程语言。 关键词变量全局变量: 在默认情况下,变量总是认为是全局的。全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。如果你想删除一个全局变量,只需要将变量赋值为nil。 一句话总结:变量默认全局,为初始化为nil,删除全局变量赋值为nil(和C语言置为空指针类似) Lua 变量有三种类型:全局变量、局部变量、表中的域。 Lua 中的变量全是全局变量,那怕是语句块或是函数里,除非用 local 显式声明为局部变量。局部变量的作用域为从声明位置开始到所在语句块结束。变量的默认值均为 nil。 Lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。 遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值。 x, y = y, x -- swap 'x' for 'y' a[i], a[j] = a[j], a[i] -- swap 'a[i]' for 'a[j]' 当变量个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略: 变量个数 > 值的个数 按变量个数补足nil
变量个数 < 值的个数 多余的值会被忽略
多值赋值经常用来交换变量,或将函数调用返回给变量(函数可以返回多个变量) f()返回两个值,第一个赋给a,第二个赋给b。应该尽可能的使用局部变量,有两个好处:
对 table 的索引使用方括号 []。Lua 也提供了 . 操作 --[[ 全局变量与局部变量 ]]-- local a ='喵' --局部变量作用于当前块(这里相当于脚本文件) do local b ='喵喵喵' --局部变量作用于当前块(do end块) end local f = function(param) print(a,param) c = function() --全局变量作用于全局 end end f('汪') print(a,b,c,param) Lua 数据类型Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。Lua中有8个基本类型分别为:nil、boolean、number、string、userdata、function、thread和table。 例: nilnil 类型表示一种没有任何有效值,它只有一个值 -- nil,例如打印一个没有赋值的变量,便会输出一个 nil 值,对于全局变量和 table,nil 还有一个"删除"作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉(类似于C的空指针) nil 作比较时应该加上双引号 ",因为type函数返回的是一个字符串
booleanLua把false和nil 看作是"假",其他的都为"真" numberLua默认只有一种 number 类型 -- double(双精度)类型(默认类型可以修改 luaconf.h 里的定义) string一对单引号、双引号或方括号 "[[]]" 来表示"一块"字符串 在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字 字符串连接使用的是两个点 .. 使用 # 来计算字符串的长度,放在字符串前面 tabletable 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据(相当于数组),直接初始化表 Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串(相当于map,叫做字典)。 a = {} -- 新建一个全局空表(这里用法可以理解为一个map) a["key1"] = "value1" -- key和value key = 10 -- 定义key变量 a[key] = 22 -- 将变量key作为键,22作为值 a[key] = a[key] + 11 -- 根据键修改值 --[[遍历table]]-- for k, v in pairs(a) do print(k .. " : " .. v) end 结果如下: 不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始。 local tbl = {"apple", "pear", "orange", "grape"} -- 这个table看起来像数组 for key, val in pairs(tbl) do -- 遍历它,key为table的下标 print("Key", key) end table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table项都是 nil。 function在 Lua 中,函数是被看作是"第一类值(First-Class Value)",函数可以存在变量里 function factorial1(n) -- 阶乘算法函数 if n == 0 then return 1 else return n * factorial1(n - 1) end end print(factorial1(5)) --打印factorial1函数返回的值 factorial2 = factorial1 -- 把函数factorial1作为参数赋给全局变量factorial2 print(factorial2(5)) -- 调用函数factorial2 function可以以匿名函数(anonymous function)的方式作为参数传递 function testFun(tab,fun) -- 遍历tab,并对每个key-val做fun函数处理 for k ,v in pairs(tab) do print(fun(k,v)); end end tab={key1="val1",key2="val2"}; -- 匿名函数作为参数 testFun(tab, --第一个参数为表 function(key,val) --匿名函数作为第二个参数 return key.."="..val; --匿名参数实现内容 end ); function调用方式. 方式赋值函数human更像作为表的一个属性,这个属性是function,参数是需要自己传的。 : 方式声明的函数可以通过self.的方式调用表对象的其他参数。 -- 函数调用方式 human = {}; human.money = 1000; -- .方式 human.isRich1 = function(h) return h.money>500; end -- :方式,self就代表函数所属的table function human:isRich2() return self.money>500; end print(human.isRich1(human)); print(human:isRich2()); thread在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。 线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。 userdatauserdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。 Lua 流程控制布尔表达式,除了nil和false为假其余全部为真。取反用not if(布尔表达式 1) then --[ 在布尔表达式 1 为 true 时执行该语句块 --] elseif( 布尔表达式 2) then --[ 在布尔表达式 2 为 true 时执行该语句块 --] else --[ 如果以上布尔表达式都不为 true 则执行该语句块 --] end Lua 循环whilestatements(循环体语句) 可以是一条或多条语句,condition(条件) 可以是任意表达式,在 condition(条件) 为 true 时执行循环体语句。 while(condition) do statements end repeat...until在条件进行判断前循环体都会执行一次。如果条件判断语句(condition)为 false,循环会重新开始执行,直到条件判断语句(condition)为 true 才会停止执行。 repeat statements until( condition ) forvar 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1。 for var=exp1,exp2,exp3 do <执行体> end 泛型for遍历数组,i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。 --打印数组a的所有值 a = {"one", "two", "three"} for i, v in ipairs(a) do print(i, v) end 遍历字典,k是key,v是value。 -- 遍历字典t的所有值,key一定为string所以不用加引号,value不一定为string所以要加 t = {name="Young",age = 23,sex = "girl"} for k, v in pairs(t) do print(k, v, t[k]) end 循环实例 --[[循环]]-- local a = 0 -- while死循环,每0.5秒执行一次,不影响性能 while wait(0.5) do print(a) a =a+1 end print('print loop end') -- repeat循环 repeat print(a) a = a+1 until a>10 -- for循环三个参数分别为起止值,步长 for i=1,10,1 do print(i) end --遍历数组 local t = {"Monday", "Tuesday", "Wednesday","Thursday","Friday","Saturday","Sunday"} t[1]="啦啦啦" --更改数组第一位的值 print(t[1]) for i, v in ipairs(t) do print(i, v,t[i]) end -- 遍历字典(key=value) local t2 = {Monday=1, Tuesday=2, Wednesday=3,Thursday=4,Friday=5,Saturday=6,Sunday=7} t2["Monday"]="啦啦啦~" -- 修改key为Monday的键值对的值为啦啦啦~ print(t2['Monday']) -- 打印键为Monday的键值对的值 for i, v in pairs(t2) do print(i, v,t2[i]) end Lua 函数Lua 函数主要有两种用途:
function_scope function function_name( argument1, argument2, argument3..., argumentn) function_body return result_params_comma_separated end 解析:
多返回值Lua函数可以返回多个结果值,比如string.find,其返回匹配串"开始和结束的下标"(如果不存在匹配串返回nil)。 s, e = string.find("www.runoob.com", "runoob") print(s, e) 方法内写法 function maximum (a) -- 返回table a的最大值和索引 local mi = 1 -- 最大值索引,初始为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})) 可变参数Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数。 function average(...) -- 取平均值 result = 0 -- 结果 local arg_tbl ={...} --> arg 为一个表,局部变量,将输入的过个参数封装为一个表 for i,v in ipairs(arg_tbl) do -- 遍历表 result = result + v -- 将value相加 end print("总共传入 " .. #arg .. " 个数") return result/#arg_tbl -- 将综合除以总数量 end print("平均值为",average(10,5,3,4,5,6))
运算符运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。Lua提供了以下几种运算符类型:
运算符优先级^ not - (unary) * / + - .. < > <= >= ~= == and or 字符串字符串或串(String)是由数字、字母、下划线组成的一串字符。 Lua 语言中字符串可以使用以下三种方式来表示:
转义字符字符串操作string.upper(argument) -- 字符串全部转为大写字母 string.lower(argument) -- 字符串全部转为小写字母 string.gsub(mainString,findString,replaceString,num) -- 在字符串中替换,mainString为要替换的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数(可以忽略,则全部替换) string.find (str, substr, [init, [end]]) --在一个指定的目标字符串中搜索指定的内容(第三个参数为索引),返回其具体位置。不存在则返回 nil。 string.reverse(arg) -- 字符串反转 string.format(...) -- 返回一个类似printf的格式化字符串 string.char(arg) 和 string.byte(arg[,int]) -- char 将整型数字转成字符并连接, byte 转换字符为整数值(可以指定某个字符,默认第一个字符)。 string.len(arg) -- 计算字符串长度。 string.rep(string, n) -- 返回字符串string的n个拷贝 .. -- 链接两个字符串 string.gmatch(str, pattern) -- 回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。 string.match(str, pattern, init) -- string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1。 在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil。 string.format字符串格式化 pattern匹配模式 数组数组,就是相同数据类型的元素按一定顺序排列的集合,可以是一维数组和多维数组。Lua 数组的索引键值可以使用整数表示,数组的大小不是固定的。 一维数组一维数组是最简单的数组,其逻辑结构是线性表。一维数组可以用for循环出数组中的元素 array = {"Lua", "Tutorial"} for i= 0, 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 迭代器泛型 for 迭代器泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。泛型 for 迭代器提供了集合的 key/value 对,语法格式如下: for k, v in pairs(t) do print(k, v) end 无状态的迭代器无状态的迭代器是指不保留任何状态的迭代器,因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价。每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。这种无状态迭代器的典型的简单的例子是ipairs,它遍历数组的每一个元素。 function square(iteratorMaxCount,currentNumber) if currentNumber<iteratorMaxCount then currentNumber = currentNumber+1 return currentNumber, currentNumber*currentNumber end end for i,n in square,3,0 do print(i,n) end table表Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用"format"来索引table string。 table操作 获取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 模块与包模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。 Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。以下为创建自定义模块 module.lua,文件代码格式如下: -- 文件名为 module.lua -- 定义一个名为 module 的模块(其实就是一个全局变量) module = {} -- 定义一个常量 module.constant = "这是一个常量" -- 定义一个函数 function module.func1() io.write("这是一个公有函数!\n") end local function func2() print("这是一个私有函数!") end function module.func3() func2() end return module -- 返回对象(把开始定义的那个全局变量在最末尾处返回) require 函数require("<模块名>") --写法一 require "<模块名>" --写法二 用法一,全局要用 -- main.lua 文件 -- module 模块为上文提到到 module.lua require("module") -- 在最上面声明,相当于java的import print(module.constant) -- module.lua文件中声明的全局变量名module.变量名 module.func3() -- module.lua文件中声明的全局变量名module.函数名 用法二,局部要用 -- main2.lua 文件 -- module 模块为上文提到到 module.lua -- 别名变量 m local m = require("module") -- 把require函数返回module.lua文件中返回的全局变量module并赋值给本地变量m print(m.constant) m.func3() 加载机制对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。 require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。 当然,如果没有 LUA_PATH 这个环境变量,也可以自定义设置,在当前用户根目录下打开 .profile 文件(没有则创建,打开 .bashrc 文件也可以),例如把 "~/lua/" 路径加入 LUA_PATH 环境变量里: #LUA_PATH export LUA_PATH="~/lua/?.lua;;" 文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。 接着,更新环境变量参数,使之立即生效。 source ~/.profile 这时假设 package.path 的值是: /Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua 那么调用 require("module") 时就会尝试打开以下文件目录去搜索目标。 /Users/dengjoe/lua/module.lua; ./module.lua /usr/local/share/lua/5.1/module.lua /usr/local/share/lua/5.1/module/init.lua /usr/local/lib/lua/5.1/module.lua /usr/local/lib/lua/5.1/module/init.lua 如果找过目标文件,则会调用 package.loadfile 来加载模块。否则,就会去找 C 程序库。 搜索的文件路径是从全局变量 package.cpath 获取,而这个变量则是通过环境变量 LUA_CPATH 来初始。 搜索的策略跟上面的一样,只不过现在换成搜索的是 so 或 dll 类型的文件。如果找得到,那么 require 就会通过 package.loadlib 来加载它。 C包
全部评论
专题导读
热门推荐
热门话题
阅读排行榜
|
请发表评论