programming in lua (1)

《programming in lua》第二版第 1-2 章。

运行环境

这里使用的 lua 版本是 5.1.4,操作系统是 debian 6.0,

到 lua 的官网下载源码包,因为是 ANSI C 写成的解析器,所以在各个平台上编译都很方便。编译之后会在源码目录里的 src 下生成两个可执行文件:lua 和 luac,其中 lua 用来解析脚本,luac 用来把脚本编译成二进制文件。在源码包里也带有一些例子,在 test 目录下。例如可以用下面的命令来运行 test 下的例子(假设当前目录为解压后的源码根目录):

./src/lua test/hello.lua

或者使用 luac 把脚本转换成二进制文件:

./src/luac test/hello.lua

默认的输出文件是 luac.out。接着可以使用 lua 来运行这个二进制文件:

./src/lua luac.out

得到的结果和直接运行脚本的结果一样,不过二进制文件的速度要快些。还有一种方法是直接执行 lua 语句:

lua -e "print(\"Hello, world.\")"

第一个 lua 程序

print("Hello, world!")

一个 lua 脚本或者在交互模式下的一行代码叫做块(chunk),块与块之间可以通过行来分隔,也可以通过分号来分隔,甚至写在同一行上的两条语句可以仅使用空格分隔。

变量命名规则和 c 差不多,都是数字,字母,下划线的组合,并且第一个字符不能是数字。保留的关键字有下面这些:

and      break    do    else        elseif
end      false    for   function    if
in       local    nil   not         or
repeat   return   then  true        until
while

单行注释使用两个连字符开头;多行注释看着有点奇怪:

-- the first program in lua

--[[
multiline comment
--]]

print("Hello, world.")

可以通过命令行向 lua 脚本传递参数。在 lua 脚本中有一个 arg 数组保存传递进来的参数。例如执行下面的命令:

lua script a b

arg 数组的各个值如下:

arg[-1] = lua
arg[0] = script
arg[1] = a
arg[2] = b

类型

lua 是一种动态类型的语言,变量在使用前不需要声明,初始值为 nil。在 lua 中变量是没有类型的,只有变量中保存的值才有类型。lua 中有 8 种基本类型:nil,boolean,number,string,userdata,function,thread,table。通过 type() 函数可以获取变量当前保存的值的类型:

print(type(a)) -- nil

a = 10
print(type(a)) -- number

a = "abc"
print(type(a)) -- string

a = print
print(type(a)) -- function

print(type(type(a))) -- string

无论 a 是什么类型,最后的语句总是输出“string”,因为 type() 的返回值是 string 类型。

boolean 只有两种取值:true 和 false。除了 nil 和 false 的值为 false 之外,其它的值均为 true(0 和空字符串也为真,这点与 c 不一样)。

number 类型代表所有实数,不区分整型和浮点型(单精度或双精度)。number 型也可以采用科学计数法,如 2.5e12 等。

string 类型可以使用单引号或双引号来界定,如果字符串中有相同的引号可以使用反斜杠转义(例如“a = "abc\"d"”这样的),或者使用不同于字符串内引号的另一种引号(例如“a = 'abc"d'”或者“a = "abc'd"”)。lua 也有类似 c 中的一些特殊转义字符,如换行“\n”,制表“\t”等。如果反斜杠后跟数值表示某个字符的 ascii 值,例如“print("\99")”会打印字符“c”。要使用多行字符串的话可以使用符号“[[”和“]]”,就像使用多行注释一样:

multilines = [[
<html>
<title>page</title>
<body>hello</body>
</html>
]]

print(multilines)

但是如果字符串中含有“a[b[c]]”这样包含“]]”的字符串的话上面的方法就不起作用了。从 5.1 版本起,lua 支持在第一个“[[”的两个“[”之间添加若干个“=”作为起始标志,两个“]”之间拥有相同数量的“=”的“]]”作为对应的结束标志,像下面这样:

multilines = [=[
a[b[c]]
]=]

print(multilines)

“[[”和“]]”之间的“=”可以为任意数量,但数量一定要相等。同样的语法也可以用在注释中(即在“--[[”的两个“[”中添加“=”,同样结束的位置“--]]”的两个“]”中也要有相同数量的“=”)。

lua 提供了 string 到 number 的自动转换,例如“print("10" + 1)”输出“11”,但是“print("hello" + 1)”会报错,原因是不能将字符串“hello”转换成数值。字符串连接符“..”可以把数值转换成字符串,例如“print(10 .. 20)”会输出“1020”(注意“..”两边有空格)。总的来说,上面这些隐式转换都不是好习惯,如果要进行转换最好使用函数显式转换,例如转换成数值可以使用函数 tonumber(),转换成 string 可以使用 tostring() 等。

在 lua5.1 之后可以使用“#”来获取 string 的长度,例如“print(#"hello")”的输出是“5”。

table 是 lua 中唯一的数据结构,是一种关联数组,而且 table 中的 key 可以是不同的类型:

a = {} -- create a table and store its reference in 'a'
a["x"] = 10
print(a["x"]) -- 10
a[20] = "k"
print(a[20]) -- k

变量 a 只是保存对 table 的一个引用,如果把 a 赋值给另一个变量 b,那么 a 和 b 指向的是同一个 table:

a = {} -- create a table and store its reference in 'a'
a["x"] = 10
b = a
print(b["x"]) -- 10
b["x"] = 5
print(a["x"]) -- 5

通过把 nil 赋给变量可以删除一个变量所指向的内容,lua 的 garbage collector 会将无用的内存收集起来重新投入使用。

另外一种访问 table 元素的方法有点像访问结构体成员的“.”操作符,也即“a.key”相当于“a["key"]”:

y = "x"
a.y = 10 -- a["x"] = 10
print(a.x) -- print(a["x"])
print(a.y) -- nil

“.”后面的是 key 而不是指向 key 的变量的名称。

function 可以作为参数传递,也可以作为返回值。

userdata 是用户自定义的 c 语言数据类型,可以存储在 lua 变量中,lua 中只定义了赋值和判断是否相等两种操作。

Comments (3)

回复 xyz 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注