
LUA脚本语言
文章平均质量分 65
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
511遇见
不一样的遇见。
展开
-
易语言调用lua脚本及lua5.3模块封装调用
lua脚本优点快速开发、容易部署、易学易用、动态代码1.Lua在脚本语言中是运行时速度最快的。Python2.集成Lua只会增加极少的内存占用率。3.只需要加载脚本,不需要每次编译,不需要加载资源,只需要启动4.Lua交互性好,特别是C5.lua文件小,200kb6.LUA并不是一门主打语言,而是寄生于强大语言的辅助语言。产品定位和功能取决于宿主语言。(宿主语言可以是 VC、DELPHI、VB、PB、易语言)...转载 2022-06-16 10:52:08 · 4820 阅读 · 1 评论 -
易语言lua通过luacom实现大漠脚本及多线程
易语言lua通过luacom实现大漠脚本及多线程原创 2022-06-16 10:30:51 · 3100 阅读 · 0 评论 -
LUA教程环境非全局的环境 -61
全局环境的一个问题是,任何修改都会影响你的程序的所有部分。例如,当你安装一个metatable去控制全局访问时,你的整个程序都必须遵循同一个指导方针。如果你想使用标准库,标准库中可能使用到没有声明的全局变量,你将碰到坏运。Lua 5.0允许每个函数可以有自己的环境来改善这个问题,听起来这很奇怪;毕竟,全局变量表的目的就是为了全局性使用。然而在Section 15.4我们将看到这个机制带来很多有趣的结构,全局的值依然是随处可以获取的。可以使用setfenv函数来改变一个函数的环境。Setfenv接受.原创 2020-07-16 09:56:41 · 2584 阅读 · 0 评论 -
LUA教程环境声明全局变量 -60
全局变量不需要声明,虽然这对一些小程序来说很方便,但程序很大时,一个简单的拼写错误可能引起bug并且很难发现。然而,如果我们喜欢,我们可以改变这种行为。因为Lua所有的全局变量都保存在一个普通的表中,我们可以使用metatables来改变访问全局变量的行为。setmetatable(_G, { __newindex = function (_, n) error("attempt to write to undeclared variable "..n, 2) end,原创 2020-07-16 09:53:41 · 2661 阅读 · 0 评论 -
LUA教程表使用动态名字访问全局变量 -59
Lua用一个名为environment普通的表来保存所有的全局变量。(更精确的说,Lua在一系列的environment中保存他的“global”变量,但是我们有时候可以忽略这种多样性)这种结果的优点之一是他简化了Lua的内部实现,因为对于所有的全局变量没有必要非要有不同的数据结构。另一个(主要的)优点是我们可以像其他表一样操作这个保存全局变量的表。为了简化操作,Lua将环境本身存储在一个全局变量_G中,(_G._G等于_G)。例如,下面代码打印在当前环境中所有的全局变量的名字:for n in p.原创 2020-07-16 09:50:49 · 2118 阅读 · 0 评论 -
LUA教程表相关的Metamethods 只读表 -58
采用代理的思想很容易实现一个只读表。我们需要做得只是当我们监控到企图修改表时候抛出错误。通过__index metamethod,我们可以不使用函数而是用原始表本身来使用表,因为我们不需要监控查寻。这是比较简单并且高效的重定向所有查询到原始表的方法。但是,这种用法要求每一个只读代理有一个单独的新的metatable,使用__index指向原始表:function readOnly (t) local proxy = {} local mt = { -- create .原创 2020-07-16 09:47:30 · 1334 阅读 · 0 评论 -
LUA教程表相关的Metamethods 监控表 -57
__index和__newindex都是只有当表中访问的域不存在时候才起作用。捕获对一个表的所有访问情况的唯一方法就是保持表为空。因此,如果我们想监控一个表的所有访问情况,我们应该为真实的表创建一个代理。这个代理是一个空表,并且带有__index和__newindex metamethods,由这两个方法负责跟踪表的所有访问情况并将其指向原始的表。假定,t是我们想要跟踪的原始表,我们可以:t = {} -- original table (created somewhere)-- keep原创 2020-07-16 09:44:48 · 1575 阅读 · 1 评论 -
LUA教程表相关的Metamethods 有默认值的表 -56
在一个普通的表中任何域的默认值都是nil。很容易通过metatables来改变默认值:function setDefault (t, d) local mt = {__index = function () return d end} setmetatable(t, mt)end tab = {x=10, y=20}print(tab.x, tab.z) --> 10 nilsetDefault(tab, 0)print(tab.x, tab.z) .原创 2020-07-16 09:33:22 · 1678 阅读 · 0 评论 -
LUA教程表相关的Metamethods The __index Metamethod-55
前面说过,当我们访问一个表的不存在的域,返回结果为nil,这是正确的,但并不一定正确。实际上,这种访问触发lua解释器去查找__index metamethod:如果不存在,返回结果为nil;如果存在则由__index metamethod返回结果。这个例子的原型是一种继承。假设我们想创建一些表来描述窗口。每一个表必须描述窗口的一些参数,比如:位置,大小,颜色风格等等。所有的这些参数都有默认的值,当我们想要创建窗口的时候只需要给出非默认值的参数即可创建我们需要的窗口。第一种方法是,实现一个表的构造器,对原创 2020-07-15 10:16:55 · 1742 阅读 · 0 评论 -
LUA教程库定义的Metamethods-54
在一些库中,在自己的metatables中定义自己的域是很普遍的情况。到目前为止,我们看到的所有metamethods都是Lua核心部分的。有虚拟机负责处理运算符涉及到的metatables和为运算符定义操作的metamethods。但是,metatable是一个普通的表,任何人都可以使用。tostring是一个典型的例子。如前面我们所见,tostring以简单的格式表示出table:print({}) --> table: 0x8062ac0(注意:print函数总是调用to.原创 2020-07-15 10:14:15 · 2040 阅读 · 0 评论 -
LUA教程关系运算的Metamethods-53
Metatables也允许我们使用metamethods:__eq(等于),__lt(小于),和__le(小于等于)给关系运算符赋予特殊的含义。对剩下的三个关系运算符没有专门的metamethod,因为Lua将a ~= b转换为not (a == b);a > b转换为b < a;a >= b转换为 b <= a。(直到Lua 4.0为止,所有的比较运算符被转换成一个,a <= b转为not (b < a)。然而这种转换并不一致正确。当我们遇到偏序(partial .原创 2020-07-15 10:10:14 · 1406 阅读 · 0 评论 -
LUA教程算术运算的Metamethods-52
这一部分我们通过一个简单的例子介绍如何使用metamethods。假定我们使用table来描述结合,使用函数来描述集合的并操作,交集操作,like操作。我们在一个表内定义这些函数,然后使用构造函数创建一个集合:Set = {}function Set.new (t) local set = {} for _, l in ipairs(t) do set[l] = true end return setend function Set.union (a,b) ..原创 2020-07-15 10:06:54 · 1831 阅读 · 1 评论 -
LUA教程Metatables and Metamethods-51
Lua中的table由于定义的行为,我们可以对key-value对执行加操作,访问key对应的value,遍历所有的key-value。但是我们不可以对两个table执行加操作,也不可比较两个表的大小Metatables允许我们改变table的行为,例如,使用Metatables我们可以定义Lua如何计算两个table的相加操作a+b。当Lua试图对两个表进行相加时,他会检查两个表是否有一个表有Metatable,并且检查Metatable是否有__add域。如果找到则调用这个__add函数(所谓的M.原创 2020-07-15 10:03:02 · 1429 阅读 · 0 评论 -
LUA教程保存带循环的table-50
针对普通拓扑概念上的带有循环表和共享子表的table,我们需要另外一种不同的方法来处理。构造器不能很好地解决这种情况,我们不使用。为了表示循环我们需要将表名记录下来,下面我们的函数有两个参数:table和对应的名字。另外,我们还必须记录已经保存过的table以防止由于循环而被重复保存。我们使用一个额外的table来记录保存过的表的轨迹,这个表的下表索引为table,而值为对应的表名。我们做一个限制:要保存的table只有一个字符串或者数字关键字。下面的这个函数序列化基本类型并返回结果。functi原创 2020-07-15 10:00:05 · 1797 阅读 · 0 评论 -
LUA教程保存不带循环的table-49
根据表的结构不同,采取的方法也有很多。没有一种单一的算法对所有情况都能很好地解决问题。简单的表不仅需要简单的算法而且输出文件也需要看起来美观。第一次尝试如下:function serialize (o) if type(o) == "number" then io.write(o) elseif type(o) == "string" then io.write(string.format("%q", o)) elseif type(o) =.原创 2020-07-15 09:55:36 · 1434 阅读 · 0 评论 -
LUA教程序列化-48
我们经常需要序列化一些数据,为了将数据转换为字节流或者字符流,这样我们就可以保存到文件或者通过网络发送出去。我们可以在Lua代码中描述序列化的数据,在这种方式下,我们运行读取程序即可从代码中构造出保存的值。通常,我们使用这样的方式varname =来保存一个全局变量的值。varname部分比较容易理解,下面我们来看看如何写一个产生值的代码。对于一个数值来说:function serialize (o) if type(o) == "number" then io.writ..原创 2020-07-15 09:51:06 · 2273 阅读 · 0 评论 -
LUA教程数据文件与持久化-47
当我们处理数据文件的,一般来说,写文件比读取文件内容来的容易。因为我们可以很好的控制文件的写操作,而从文件读取数据常常碰到不可预知的情况。一个健壮的程序不仅应该可以读取存有正确格式的数据还应该能够处理坏文件(译者注:对数据内容和格式进行校验,对异常情况能够做出恰当处理)。正因为如此,实现一个健壮的读取数据文件的程序是很困难的。正如我们在Section 10.1(译者:第10章Complete Examples)中看到的例子,文件格式可以通过使用Lua中的table构造器来描述。我们只需要在写数据的稍微.原创 2020-07-15 09:48:20 · 1374 阅读 · 0 评论 -
LUA教程字符串缓冲-46
假定你要拼接很多个小的字符串为一个大的字符串,比如,从一个文件中逐行读入字符串。你可能写出下面这样的代码:-- WARNING: bad code ahead!!local buff = ""for line in io.lines() do buff = buff .. line .. "\n"end尽管这段代码看上去很正常,但在Lua中他的效率极低,在处理大文件的时候,你会明显看到很慢,例如,需要花大概1分钟读取350KB的文件。(这就是为什么Lua专门提供了io.read(*a原创 2020-07-15 09:43:06 · 1418 阅读 · 0 评论 -
LUA教程集合和包-45
假定你想列出在一段源代码中出现的所有标示符,某种程度上,你需要过滤掉那些语言本身的保留字。一些C程序员喜欢用一个字符串数组来表示,将所有的保留字放在数组中,对每一个标示符到这个数组中查找看是否为保留字,有时候为了提高查询效率,对数组存储的时候使用二分查找或者hash算法。Lua中表示这个集合有一个简单有效的方法,将所有集合中的元素作为下标存放在一个table里,下面不需要查找table,只需要测试看对于给定的元素,表的对应下标的元素值是否为nil。比如:reserved = { ["whi原创 2020-07-14 08:46:26 · 1919 阅读 · 0 评论 -
LUA教程队列和双向队列-44
虽然可以使用Lua的table库提供的insert和remove操作来实现队列,但这种方式实现的队列针对大数据量时效率太低,有效的方式是使用两个索引下标,一个表示第一个元素,另一个表示最后一个元素。function ListNew () return {first = 0, last = -1}end为了避免污染全局命名空间,我们重写上面的代码,将其放在一个名为list的table中:List = {}function List.new () return {first原创 2020-07-14 08:44:26 · 2103 阅读 · 0 评论 -
LUA教程链表-43
Lua中用tables很容易实现链表,每一个节点是一个table,指针是这个表的一个域(field),并且指向另一个节点(table)。例如,要实现一个只有两个域:值和指针的基本链表,代码如下:根节点:list = nil在链表开头插入一个值为v的节点:list = {next = list, value = v}要遍历这个链表只需要:local l = listwhile l do print(l.value) l = l.nextend原文:LUA一原创 2020-07-14 08:41:58 · 2101 阅读 · 0 评论 -
LUA教程完矩阵和多维数组-42
Lua中有两种表示矩阵的方法,一是“数组的数组”。也就是说,table的每个元素是另一个table。例如,可以使用下面代码创建一个n行m列的矩阵:mt = {} -- create the matrixfor i=1,N do mt[i] = {} -- create a new row for j=1,M do mt[i][j] = 0 endend由于Lua中table是对象,所以每一行我们必须显式地创建一个table,比起c原创 2020-07-14 08:39:11 · 2654 阅读 · 0 评论 -
LUA教程完数据结构数组-41
在lua中通过整数下标访问table中元素,即是数组。并且数组大小不固定,可动态增长。通常我们初始化数组时,就间接地定义了数组的大小,例如:a = {} -- new arrayfor i=1, 1000 do a[i] = 0end数组a的大小为1000,访问1-1000范围外的值,将返回nil。数组下标可以根据需要,从任意值开始,比如:-- creates an array with indices from -5 to 5a = {}for i=-5, 5原创 2020-07-14 08:35:23 · 1587 阅读 · 0 评论 -
LUA教程完整示例马尔可夫链算法-40
第二个例子是马尔可夫链算法的实现,我们的程序以前n(n=2)个单词串为基础随机产生一个文本串。程序的第一部分读出原文,并且对没两个单词的前缀建立一个表,这个表给出了具有那些前缀的单词的一个顺序。建表完成后,这个程序利用这张表生成一个随机的文本。在此文本中,每个单词都跟随着它的的前两个单词,这两个单词在文本中有相同的概率。这样,我们就产生了一个非常随机,但并不完全随机的文本。例如,当应用这个程序的输出结果会出现“构造器也可以通过表构造器,那么一下几行的插入语对于整个文件来说,不是来存储每个功能的内容,而是来原创 2020-07-14 08:32:48 · 1398 阅读 · 0 评论 -
LUA教程完整示例Lua作为数据描述语言使用-39
慢慢地,Lua正被世界上越来越多的人使用。Lua官方网站的数据库中保存着一些“使用了Lua”的项目的信息。在数据库中,我们用一个构造器以自动归档的方式表示每个工程入口,代码如下:entry{ title = "Tecgraf", org = "Computer Graphics Technology Group, PUC-Rio", url = "http://www.tecgraf.puc-rio.br/", contact = "Waldemar Celes",原创 2020-07-14 08:29:09 · 2242 阅读 · 0 评论 -
LUA教程非抢占式多线程-38
如前面所见,Lua中的协同是一协作的多线程,每一个协同等同于一个线程,yield-resume可以实现在线程中切换。然而与真正的多线程不同的是,协同是非抢占式的。当一个协同正在运行时,不能在外部终止他。只能通过显示的调用yield挂起他的执行。对于某些应用来说这个不存在问题,但有些应用对此是不能忍受的。不存在抢占式调用的程序是容易编写的。不需要考虑同步带来的bugs,因为程序中的所有线程间的同步都是显示的。你仅仅需要在协同代码超出临界区时调用yield即可。对非抢占式多线程来说,不管什么时候只要有一个线原创 2020-07-14 08:11:12 · 1852 阅读 · 0 评论 -
LUA教程用作迭代器的协同-37
我们可以将循环的迭代器看作生产者-消费者模式的特殊的例子。迭代函数产生值给循环体消费。所以可以使用协同来实现迭代器。协同的一个关键特征是它可以不断颠倒调用者与被调用者之间的关系,这样我们毫无顾虑的使用它实现一个迭代器,而不用保存迭代函数返回的状态。我们来完成一个打印一个数组元素的所有的排列来阐明这种应用。直接写这样一个迭代函数来完成这个任务并不容易,但是写一个生成所有排列的递归函数并不难。思路是这样的:将数组中的每一个元素放到最后,依次递归生成所有剩余元素的排列。代码如下:function per原创 2020-07-14 08:05:36 · 1305 阅读 · 0 评论 -
LUA教程管道和过滤器-36
协同最具代表性的例子是用来解决生产者-消费者问题。假定有一个函数不断地生产数据(比如从文件中读取),另一个函数不断的处理这些数据(比如写到另一文件中),函数如下:function producer () while true do local x = io.read() -- produce new value send(x) -- send to consumer endendfunction consu.原创 2020-07-14 08:02:41 · 1646 阅读 · 0 评论 -
LUA教程错误信息和回跟踪(Tracebacks)-34
虽然你可以使用任何类型的值作为错误信息,通常情况下,我们使用字符串来描述遇到的错误。如果遇到内部错误(比如对一个非table的值使用索引下标访问)Lua将自己产生错误信息,否则Lua使用传递给error函数的参数作为错误信息。不管在什么情况下,Lua都尽可能清楚的描述问题发生的缘由。local status, err = pcall(function () a = 'a'+1 end)print(err)--> stdin:1: attempt to perform arithmetic o原创 2020-07-13 09:51:50 · 2901 阅读 · 0 评论 -
LUA教程异常和错误处理-33
多应用中,不需要在Lua进行错误处理,一般有应用来完成。通常应用要求Lua运行一段chunk,如果发生异常,应用根据Lua返回的错误代码进行处理。在控制台模式下的Lua解释器如果遇到异常,打印出错误然后继续显示提示符等待下一个命令。如果在Lua中需要处理错误,需要使用pcall函数封装你的代码。假定你想运行一段Lua代码,这段代码运行过程中可以捕捉所有的异常和错误。第一步:将这段代码封装在一个函数内function foo () ... if unexpected_con.原创 2020-07-13 09:49:06 · 3103 阅读 · 0 评论 -
LUA教程错误-32
Errare humanum est(拉丁谚语:犯错是人的本性)。所以我们要尽可能的防止错误的发生,Lua经常作为扩展语言嵌入在别的应用中,所以不能当错误发生时简单的崩溃或者退出。相反,当错误发生时Lua结束当前的chunk并返回到应用中。当Lua遇到不期望的情况时就会抛出错误,比如:两个非数字进行相加;调用一个非函数的变量;访问表中不存在的值等(可以通过metatables修改这种行为,后面介绍)。你也可以通过调用error函数显式地抛出错误,error的参数是要抛出的错误信息。print ".原创 2020-07-13 09:46:39 · 1868 阅读 · 0 评论 -
LUA教程C Packages-31
Lua和C是很容易结合的,使用C为Lua写包。与Lua中写包不同,C包在使用以前必须首先加载并连接,在大多数系统中最容易的实现方式是通过动态连接库机制,然而动态连接库不是ANSI C的一部分,也就是说在标准C中实现动态连接是很困难的。通常Lua不包含任何不能用标准C实现的机制,动态连接库是一个特例。我们可以将动态连接库机制视为其他机制之母:一旦我们拥有了动态连接机制,我们就可以动态的加载Lua中不存在的机制。所以,在这种特殊情况下,Lua打破了他平台兼容的原则而通过条件编译的方式为一些平台实现了动态连接原创 2020-07-13 09:42:40 · 1481 阅读 · 0 评论 -
LUA教程require函数-30
Lua提供高级的require函数来加载运行库。粗略的说require和dofile完成同样的功能但有两点不同:1. require会搜索目录加载文件2. require会判断是否文件已经加载避免重复加载同一文件。由于上述特征,require在Lua中是加载库的更好的函数。require使用的路径和普通我们看到的路径还有些区别,我们一般见到的路径都是一个目录列表。require的路径是一个模式列表,每一个模式指明一种由虚文件名(require的参数)转成实文件名的方法。更明确地说,每一个模式是.原创 2020-07-13 09:40:21 · 2960 阅读 · 0 评论 -
LUA教程编译·运行·错误信息-29
虽然我们把Lua当作解释型语言,但是Lua会首先把代码预编译成中间码然后再执行(很多解释型语言都是这么做的)。在解释型语言中存在编译阶段听起来不合适,然而,解释型语言的特征不在于他们是否被编译,而是编译器是语言运行时的一部分,所以,执行编译产生的中间码速度会更快。我们可以说函数dofile的存在就是说明可以将Lua作为一种解释型语言被调用。前面我们介绍过dofile,把它当作Lua运行代码的chunk的一种原始的操作。dofile实际上是一个辅助的函数。真正完成功能的函数是loadfile;与dofi.原创 2020-07-13 09:37:12 · 2693 阅读 · 0 评论 -
LUA教程真正的迭代器-28
迭代器的名字有一些误导,因为它并没有迭代,完成迭代功能的是for语句,也许更好的叫法应该是生成器(generator);但是在其他语言比如java、C++迭代器的说法已经很普遍了,我们也就沿用这个术语。有一种方式创建一个在内部完成迭代的迭代器。这样当我们使用迭代器的时候就不需要使用循环了;我们仅仅使用每一次迭代需要处理的任务作为参数调用迭代器即可,具体地说,迭代器接受一个函数作为参数,并且这个函数在迭代器内部被调用。作为一个具体的例子,我们使用上述方式重写allwords迭代器:function原创 2020-07-13 09:32:01 · 1535 阅读 · 0 评论 -
LUA教程多状态的迭代器-27
很多情况下,迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,最简单的方法是使用闭包,还有一种方法就是将所有的状态信息封装到table内,将table作为迭代器的状态常量,因为这种情况下可以将所有的信息存放在table内,所以迭代函数通常不需要第二个参数。下面我们重写allwords迭代器,这一次我们不是使用闭包而是使用带有两个域(line, pos)的table。开始迭代的函数是很简单的,他必须返回迭代函数和初始状态:local iterator -- to be def原创 2020-07-13 09:28:51 · 1357 阅读 · 0 评论 -
LUA教程无状态的迭代器-26
无状态的迭代器是指不保留任何状态的迭代器,因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价。每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。这种无状态迭代器的典型的简单的例子是ipairs,他遍历数组的每一个元素。a = {"one", "two", "three"}for i, v in ipairs(a) do print(i, v)end迭代的状态包括被遍历的表(循环过程中不会改变.原创 2020-07-13 09:25:48 · 1830 阅读 · 0 评论 -
LUA教程迭代器与闭包-24
迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是他知道来自于哪里和将要前往哪里。闭包提供的机制可以很容易实现这个任务。记住:闭包是一个内部函数,它可以访问一个或者多个外部函数的外部局部变量。每次闭包的成功调用后这些外部局部变量都保存他们的值(状态)。当然如果要创建一个闭包必须要创建其外部局部变量。所以一个典型的闭包的结构包含两个函数:一个是闭包自己;.原创 2020-07-13 09:22:54 · 1324 阅读 · 0 评论 -
LUA教程正确的尾调用(Proper Tail Calls)-23
Lua中函数的另一个有趣的特征是可以正确的处理尾调用(proper tail recursion,一些书使用术语“尾递归”,虽然并未涉及到递归的概念)。尾调用是一种类似在函数结尾的goto调用,当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用。例如:function f(x) return g(x)endg的调用是尾调用。例子中f调用g后不会再做任何事情,这种情况下当被调用函数g结束时程序不需要返回到调用者f;所以尾调用之后程序不需要在栈中保留关于调用者的任何信息。.原创 2020-07-12 10:14:56 · 1600 阅读 · 1 评论 -
LUA教程非全局函数-22
Lua中函数可以作为全局变量也可以作为局部变量,我们已经看到一些例子:函数作为table的域(大部分Lua标准库使用这种机制来实现的比如io.read、math.sin)。这种情况下,必须注意函数和表语法:1. 表和函数放在一起Lib = {}Lib.foo = function (x,y) return x + y endLib.goo = function (x,y) return x - y end2. 使用表构造函数Lib = { foo = function ..原创 2020-07-12 10:11:28 · 1458 阅读 · 0 评论