programming in lua (12)

第 9 章和第 30 章部分内容,都是讲线程相关的。

基本概念

lua 中的 coroutine 和我们通常说的“线程”概念相近,但是这里的 coroutine 并不是真正的线程,在某个时刻只有一个 coroutine 在执行。lua 将 coroutine 的所有函数都放在一个叫“coroutine”的 table 中,下面来看一下这些函数。

co = coroutine.create(function () print("hello") end)
print(co) -- thread: 0x11fa810
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- hello
print(coroutine.status(co)) -- dead

create() 接收一个函数作为参数,创建一个对应的 …

阅读全文…

programming in lua (11)

第 29 章和 31 章。这两章都是讲资源管理的,就放一起看了。

userdata 可能是用户自己分配的一段内存(内存里可能有一个域是文件描述符,可能是一个指向另外一段内存的指针,等等),当这段 userdata 被释放时,其中包含的其它资源也需要被释放(如需要关闭文件,释放另一段内存等)。某些语言提供了一种叫做“finalizer”的机制来完成这件事,在 lua 中对应的是一个“__gc”的域,当某个 userdata 被 lua 回收时,如果它对应的 metatable 中有“__gc”这个域,则这个域所指向的函数(通常指向的是函数)将会被调用,这样用户就能释放和 userdata 相关联的内容。

目录遍历迭代器

第 26 章实现过一个目录遍历的程序,程序每次返回一个包含所有目录项的 table。这里我们将要实现一个迭代器,每次只返回一个目录:

for dname in dir(".") do
    print(dname)
end

c 语言中遍历目录的步骤:首先使用 opendir() 函数打开目录返回一个指向 DIR 结构体的指针,然后使用 readdir() 每次读取一个目录,读取完所有目录后使用 closedir() …

阅读全文…

programming in lua (10)

第 28 章。这章主要是讲怎样在 lua 中使用 c 语言中自定义的数据结构。

先看一个简单的例子:boolean 数组。在 lua 中可以使用 table 来存储,在 c 语言中由于每个变量只占一个 bit,使用的内存只占用 table 实现的 3%。

程序使用如下的数据结构和相关的宏定义:

#include <limits.h>

#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
#define I_WORD(i)     ((unsigned int)(i) / BITS_PER_WORD)
#define I_BIT(i)      (1 << ((unsigned int)(i) % BITS_PER_WORD))


阅读全文…

programming in lua (9)

第 27 章,主要介绍 c 语言和 lua 交互的一些技巧。这一章涉及到第 2 部分的一些内容。

数组操作

在 lua 中,数组是一种特殊的 table,除了可以使用 lua_settable() 和 lua_gettable() 等操作 table 的函数外,另外也有一些专门用来操作数组的函数。使用这些有针对性的函数有两个好处:一是性能上的提升,例如我们经常在循环访问数组的所有元素;二是像整数数组,字符串等常见的类型使用一些有针对性的操作会比较方便。

lua 提供了两个函数来访问指定下标的数组元素:

void lua_rawgeti (lua_State *L, int index, int key);
void lua_rawseti (lua_State *L, int index, int key);

其中 index …

阅读全文…

programming in lua (8)

第 26 章。

扩展 lua 的一个基本方法是使用 c 语言编写可供 lua 使用的函数。

当我们说 lua“调用”c 函数时,其实并不是真正地调用 c 函数,而是 c 函数遵循一定的约定从 lua 中获取参数并且把结果返回给 lua,或许叫“使用”更合适。在 lua 调用 c 函数前需要先注册 c 函数,即把 c 函数的地址传递给 lua。事实上,lua 使用 c 函数也是通过类似的栈机制,为了避免取了错误的返回值,c 函数需要返回它返回给 lua 的返回值个数(也就是说 lua 应该从栈里取几个值)。

和在 c 中使用 …

阅读全文…

programming in lua (7)

第 25 章。

lua 的一个重要的应用是作为程序配置文件的语言(configuration language)。下面通过一些例子循序渐进地说明其应用。

一个简单的例子

假设一个 c 语言程序要画一个窗口界面,窗口的长和宽可以由用户指定。要实现这个功能还有另外更简单的方法,例如使用环境变量或只包含 (key, value) 形式的普通文本文件,但是如果使用普通文本文件你还是需要对其进行解析。程序的配置文件如下:

-- conf.lua
-- define window size
width = 200
height = 300

下面的程序演示了怎样使用 lua 提供的接口来获得这两个变量的值:

#include <stdio.h>

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main(void)
{
    lua_State* 

阅读全文…

programming in lua (6)

中断了的 lua 学习再次回来了……之前学完基本语法后就不想看接下来的标准库讲解了,因为看了不用基本等于白看,没几天就忘了;但是不看的话连 lua 有什么功能都不知道,更不用说知道把 lua 用在什么地方。最近想学习用 lua 来扩展程序,因此又捡起来了,不过跳过了书中的 part II 和 part III,这里是第 24 章。顺便说一下,这里使用的 lua 版本也从 5.1.4 升到 5.2.0,不过区别应该不大。

lua 是一个嵌入式语言,就是说它不是一个单独的程序,而是一套可以在其它语言中使用的库,在前面使用过的 lua 交互程序其实是利用 lua 提供的库所实现的一个解析器。lua 可以作为 c 语言的扩展,反过来也可以用 c 语言编写模块来扩展 lua,这两种情况都使用同样的 api 进行交互。lua 与 c 主要是通过一个虚拟的“栈”来交换数据。

简单的 lua


阅读全文…

programming in lua (5)

第 8 章。

虽然我们说 lua 是一种解释语言,但是 lua 在执行前会被预编译为一种中间代码。解释执行语言的特殊之处不在于它们不需要编译执行,而是编译器是语言运行时(runtime)本身的一部分,也就是说可以执行在运行过程中动态产生的代码。

例如函数 loadstring() 接收一个字符串,返回一个可被执行的语句块(chunk):

f = loadstring("i = i + 1")

i = 10
f()
print(i) -- 11

又或者是省略赋值操作直接使用 loadstring() 的返回值:

i = 10
loadstring("i = i + 1")()
print(i) -- 11

但是直接使用的话如果出错了出错信息会比较模糊。可以使用 …

阅读全文…

programming in lua (4)

第 7 章。这一章看得不是很明白。

迭代器可以遍历一个集合中的所有元素。在 lua 中,迭代器一般都是函数,每次调用这个函数都会返回集合中的“下一个”元素,前面提到的闭包函数就是实现迭代器的很好选择:

function values (t)
   local i = 0
   return function ()
      i = i + 1
      return t[i]
   end
end

arr = {"one", "two", "three"}

iter = values(arr)
while true do
   local e = iter()
   

阅读全文…

programming in lua (3)

5-6 章。

函数

函数是完成某一特定功能的语句集合。函数使用括号标识,括号内是传递给函数的参数。如果函数只有一个参数,且这个参数是一个字符串或者 table 的 constructor,那么括号是可选的,例如:

print("Hello")
print "hello"
print (type({x = 10, y = 20}))
print (type {x = 10, y = 20})

函数定义的语法是:

function func_name (parameter)
   body
end

如果括号中的参数多于 1 个用逗号隔开,如果没有参数就不用写。

给函数传递参数时,如果参数的个数比函数定义的个数少,则靠右的参数被赋值为 nil;如果传递的参数比函数定义的个数多,则多出来的值被忽略:

function func(a, b, c)
   

阅读全文…