随笔分类 - Lua编程
摘要:之前已经说了很多,我目前的观点还是那样,在嵌入式脚本中,Lua是最优秀、最高效的,如果您有不同的观点,欢迎指正并讨论,切勿吐槽。这个系列完全来自于《Programming in Lua》,您可以将其视为本人的读书笔记。相比而言,如果您已经掌握了Lua,但仍然不是非常熟练,请相信这个系列一定会给您的查阅以及知识点回顾带来一定程度上的方便,至少我是这样的。然而对于Lua的初学者,还是建议直接看《Programming in Lua》。最近正在做一个项目的架构设计,打算使用Lua作为插件和框架之间的粘合剂,以及硬件协议的自描述脚本,从而可以动态扩展平台可以支持的硬件设备。好了,不说太多了,还是看看.
阅读全文
摘要:在Lua中可以通过自定义类型的方式与C语言代码更高效、更灵活的交互。这里我们通过一个简单完整的示例来学习一下Lua中userdata的使用方式。需要说明的是,该示例完全来自于Programming in Lua。其功能是用C程序实现一个Lua的布尔数组,以提供程序的执行效率。见下面的代码和关键性注释。 1 #include <lua.hpp> 2 #include <lauxlib.h> 3 #include <lualib.h> 4 #include <limits.h> 5 6 #define BITS_PER_WORD (CHAR_BIT
阅读全文
摘要:1. 数组操作: 在Lua中,“数组”只是table的一个别名,是指以一种特殊的方法来使用table。出于性能原因,Lua的C API为数组操作提供了专门的函数,如: void lua_rawgeti(lua_State* L, int index, int key); void lua_rawseti(lua_State* L, int index, int key); 以上两个函数分别用于读取和设置数组中的元素值。其中index参数表示待操作的table在栈中的位置,key表示元素在table中的索引值。由于这两个函数均为原始操作,比涉及元表的table访问更快。通常而言,作为数组使用的.
阅读全文
摘要:Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性。对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数。对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L)。简单说明一下,该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数。返回值是整型,表示该C函数将返回给Lua代码的返回值数量,如果没有返回值,则return 0即可。需要说明的是,C函数无法直.
阅读全文
摘要:1. 基础: Lua的一项重要用途就是作为一种配置语言。现在从一个简单的示例开始吧。 --这里是用Lua代码定义的窗口大小的配置信息 width = 200 height = 300 下面是读取配置信息的C/C++代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <lua.hpp> 4 #include <lauxlib.h> 5 #include <lualib.h> 6 7 void load(lua_State* L, const char* fname, int
阅读全文
摘要:Lua是一种嵌入式脚本语言,即Lua不是可以单独运行的程序,在实际应用中,主要存在两种应用形式。第一种形式是,C/C++作为主程序,调用Lua代码,此时可以将Lua看做“可扩展的语言”,我们将这种应用称为“应用程序代码”。第二种形式是Lua具有控制权,而C/C++代码则作为Lua的“库代码”。在这两种形式中,都是通过Lua提供的C API完成两种语言之间的通信的。 1. 基础知识: C API是一组能使C/C++代码与Lua交互的函数。其中包括读写Lua全局变量、调用Lua函数、运行一段Lua代码,以及注册C函数以供Lua代码调用等。这里先给出一个简单的示例代码: 1 #include <
阅读全文
摘要:Lua为了保证高度的可移植性,因此,它的标准库仅仅提供了非常少的功能,特别是和OS相关的库。但是Lua还提供了一些扩展库,比如Posix库等。对于文件操作而言,该库仅提供了os.rename函数和os.remove函数。 1. 日期和时间: 在Lua中,函数time和date提供了所有的日期和时间功能。 如果不带任何参数调用time函数,它将以数字形式返回当前的日期和时间。如果以一个table作为参数,它将返回一个数字,表示该table中所描述的日期和时间。该table的有效字段如下:字段名描述year一个完整的年份month01-12day01-31hour00-23min00-59se..
阅读全文
摘要:I/O库为文件操作提供了两种不同的模型,简单模型和完整模型。简单模型假设一个当前输入文件和一个当前输出文件,他的I/O操作均作用于这些文件。完整模型则使用显式的文件句柄,并将所有的操作定义为文件句柄上的方法。 1. 简单模型: I/O库会将进程标准输入输出作为其缺省的输入文件和输出文件。我们可以通过io.input(filename)和io.output(filename)这两个函数来改变当前的输入输出文件。 1). io.write函数: 函数原型为io.write(...)。该函数将所有参数顺序的写入到当前输出文件中。如: io.write("hello","
阅读全文
摘要:1. 基础字符串函数: 字符串库中有一些函数非常简单,如: 1). string.len(s) 返回字符串s的长度; 2). string.rep(s,n) 返回字符串s重复n次的结果; 3). string.lower(s) 返回s的副本,其中所有的大写都被转换为了小写形式,其他字符不变; 4). string.upper(s) 和lower相反,将小写转换为大写; 5). string.sub(s,i,j) 提取字符串s的第i个到第j个字符。Lua中,第一个字符的索引值为1,最后一个为-1,以此类推,如: print(string.sub("[hello world]"
阅读全文
摘要:Lua采用了基于垃圾收集的内存管理机制,因此对于程序员来说,在很多时候内存问题都将不再困扰他们。然而任何垃圾收集器都不是万能的,在有些特殊情况下,垃圾收集器是无法准确的判断是否应该将当前对象清理。这样就极有可能导致很多垃圾对象无法被释放。为了解决这一问题,就需要Lua的开发者予以一定程度上的配合。比如,当某个table对象被存放在容器中,而容器的外部不再有任何变量引用该对象,对于这样的对象,Lua的垃圾收集器是不会清理的,因为容器对象仍然引用着他。如果此时针对该容器的应用仅限于查找,而不是遍历的话,那么该对象将永远不会被用到。事实上,对于这样的对象我们是希望Lua的垃圾收集器可以将其清理掉的.
阅读全文
摘要:Lua中的table就是一种对象,但是如果直接使用仍然会存在大量的问题,见如下代码:1 Account = {balance = 0}2 function Account.withdraw(v)3 Account.balance = Account.balance - v4 end5 --下面是测试调用函数6 Account.withdraw(100.00) 在上面的withdraw函数内部依赖了全局变量Account,一旦该变量发生改变,将会导致withdraw不再能正常的工作,如:1 a = Account; Account = nil2 a.withdraw(100.00) ...
阅读全文
摘要:从Lua 5.1开始,我们可以使用require和module函数来获取和创建Lua中的模块。从使用者的角度来看,一个模块就是一个程序库,可以通过require来加载,之后便得到一个类型为table的全局变量。此时的table就像名字空间一样,可以访问其中的函数和常量,如:1 require "mod"2 mod.foo()3 local m2 = require "mod2"4 local f = mod2.foo5 f() 1. require函数: require函数的调用形式为require "模块名"。该调用会返回一个由模块
阅读全文
摘要:Lua将其所有的全局变量保存在一个常规的table中,这个table被称为“环境”。它被保存在全局变量_G中。 1. 全局变量声明: Lua中的全局变量不需要声明就可以使用。尽管很方便,但是一旦出现笔误就会造成难以发现的错误。我们可以通过给_G表加元表的方式来保护全局变量的读取和设置,这样就能降低这种笔误问题的发生几率了。见如下示例代码: 1 --该table用于存储所有已经声明过的全局变量名 2 local declaredNames = {} 3 local mt = { 4 __newindex = function(table,name,value) 5 -...
阅读全文
摘要:Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加。假设a和b都是table,通过元表可以定义如何计算表达式a+b。当Lua试图将两个table相加时,它会先检查两者之一是否有元表,然后检查该元表中是否存在__add字段,如果有,就调用该字段对应的值。这个值就是所谓的“元方法”,这个函数用于计算table的和。 Lua中每个值都有一个元表。table和userdata可以有各自独立的元表,而其它数据类型的值则共享其类型所属的单一元表。缺省情况下,table在创建时没有元表,如: t = {} print(getmetatable(t)) --输.
阅读全文
摘要:1. 数据文件: 我们可以利用Lua中table的构造式来定义一种文件格式,即文件中的数据是table构造并初始化的代码,这种方式对于Lua程序而言是非常方便和清晰的,如: Entry { "Stephen Liu", "Male", "Programmer", "BS" } Entry { "Jerry Tian", "Male", "Programmer", "BS" } 需要注意的是,Entry{<code>}等价于E
阅读全文
摘要:Lua中的table不是一种简单的数据结构,它可以作为其它数据结构的基础。如数组、记录、线性表、队列和集合等,在Lua中都可以通过table来表示。 1. 数组: 使用整数来索引table即可在Lua中实现数组。因此,Lua中的数组没有固定的大小,如:1 a = {}2 for i = 1, 1000 do3 a[i] = 04 end5 print("The length of array 'a' is " .. #a)6 --The length of array 'a' is 1000 在Lua中,可以让任何数作为数组的起始索引,但通常
阅读全文
摘要:1. 编译: Lua中提供了dofile函数,它是一种内置的操作,用于运行Lua代码块。但实际上dofile只是一个辅助函数,loadfile才是真正的核心函数。相比于dofile,loadfile只是从指定的文件中加载Lua代码块,然后编译这段代码块,如果有编译错误,就返回nil,同时给出错误信息,但是在编译成功后并不真正的执行这段代码块。因此,我们可以将dofile实现为:1 function dofile(filename)2 local f = assert(loadfile(filename))3 return f()4 end 这里如果loadfile执行失败,a...
阅读全文
摘要:1. 迭代器与Closure: 在Lua中,迭代器通常为函数,每调用一次函数,即返回集合中的“下一个”元素。每个迭代器都需要在每次成功调用之间保持一些状态,这样才能知道它所在的位置和下一次遍历时的位置。从这一点看,Lua中closure机制为此问题提供了语言上的保障,见如下示例: 1 function values(t) 2 local i = 0 3 return function() 4 i = i + 1 5 return t[i] 6 end 7 end 8 t = {10, 20, 30} 9 it = values(t)10...
阅读全文
摘要:一、函数: 在Lua中函数的调用方式和C语言基本相同,如:print("Hello World")和a = add(x, y)。唯一的差别是,如果函数只有一个参数,并且该参数的类型为字符串常量或table的构造器,那么圆括号可以省略,如print "Hello World"和f {x = 20, y = 20}。 Lua为面对对象式的调用也提供了一种特殊的语法--冒号操作符。表达式o.foo(o,x)的另一种写法是o:foo(x)。冒号操作符使调用o.foo时将o隐含的作为函数的第一个参数。 Lua中函数的声明方式如下: function add(a)
阅读全文
摘要:一、表达式: 1. 算术操作符: Lua支持常规算术操作符有:二元的“+”、“-”、“*”、“/”、“^”(指数)、“%”(取模),一元的“-”(负号)。所有这些操作符都可用于实数。然而需要特别说明的是取模操作符(%),Lua中对该操作符的定义为: a % b == a - floor(a / b) * b 由此可以推演出x % 1的结果为x的小数部分,而x - x % 1的结果则为x的整数部分。类似的,x - x % 0.01则是x精确到小数点后两位的结果。 2. 关系操作符: Lua支持的关系操作符有:>、<、>=、<=、==、~=,所有这些操作符的结果均为true
阅读全文