Lua是一种动态类型的语言,在语言中没有类型定义短的语法,每个值都“携带”了其自身的类型信息。在Lua中,有8种基础数据类型:nil(空)、boolean(布尔)、number(数字)、string(字符串)、userdata(自定义类型)、function(函数)、thread(线程)和table(表)。函数type可以根据一个值返回其类型名称:
print(type(nil)) -->nil
print(type(true)) -->boolean
print(type(10.4*3)) -->number
print(type("hello world")) -->string
print(type(print)) -->function
type函数总是返回一个字符串,变量没有预定义的类型,因此,任何变量可以包含任何类型的值,函数作为第一类值(first-class value)来看待也可以赋值给某个变量,下面会详细介绍这8中数据类型。
一、nil(空)
nil是一种类型,其只有一个值nil,它的主要功能是用于区别其它任何值。典型的应用是:一个全局变量在第一次赋值前默认值就是nil,将nil赋予一个全局变量就等同于删除它。Lua将nil用于表示一种无效值(non-value)的情况,即没有任何有效值的情况。
二、boolean(布尔)
boolean类型有两个可选值:false和true。Lua将值false和nil视为假,而将除此之外的其它值视为真。
需要注意的是:Lua在条件测试中,将数字零和空字符串也都视为真,这点不同于某些脚本或者语言。
三、number(数字)
number类型用于表示实数即双精度浮点数。Lua没有整型类型,而用数字来表示32位整数。通过重新编译Lua也可以非常发年底使用其它类型来表示数字,比如:长整型long或单精度浮点数float,这点详见发行版中的luaconf.h文件。数字常量可以是普通写法(4、0.4),也可以使用科学计数法(4.57e-3、0.3e12)。
四、string(字符串)
Lua中的字符串通常表示一个字符序列。Lua完全采用8位编码,Lua字符串中的字符可以具有任何数值编码,包括数值0。也就是说,可以将任意二进制数据存储到一个字符串中。Lua的字符串是不可变的值(immutable values),不能像C语言中那样直接修改字符串的某个字符,而是应该根据修改要求来创建一个新的字符串,比如:
a = "one string"
b = string.gsub(a, "one", "another") --修改字符串的一部分
print(a) --one string
print(b) --another string
Lua的字符串与其它Lua对象(比如:table或函数等)一样,都是自动内存管理机制所管理的对象,即无需担心字符串的分配和释放而由Lua全权处理。一个字符串可以小到只包含一个字母,也可以大到包含整本书,Lua能高效地处理长字符串,在Lua程序中操作100K或1M的字符串是很常见的事情。
字符串用一对匹配的单引号或双引号来界定,建议在程序中使用相同类型的引号,除非字符串本身包含引号,那么可以使用另一种引号来界定字符串,或者使用反斜杠对引号进行转义,Lua的转义序列类似于C语言。
还可以用一对匹配的双方括号来界定一个字母字符串,就像写块注释那样。以这种形式书写的字符串可以延伸多行,且Lua不会解释其中的转义序列,如果字符串的第一个字符是换行符,则Lua会忽略它,这种写法对那种含有程序代码的字符串尤为有用,比如:
page = [[
An HTML Page
Lua
]]
write(page)
有时候字符串中可能包含这样的内容:a=b[c[i]]或者包含已经被注释掉的代码。为了解决这种问题,需要在两个方括号之间加上任意数量的等号,如:[===[,这样字符串只有遇到内嵌有相同数量等号的双右括号时才会结束,即]===],否则Lua会忽略它。通过这种方式,就可以不用对此进行转义了。同理,注释块时也可以采用这种机制,即--[===[开始,]===]结束。
Lua提供了运行时的数字与字符串的自动转换,即在一个字符串上应用算术操作时,Lua会尝试将这个字符串转换成一个数字,同样,在Lua期望一个字符串但却得到一个数字时,也会将数字转换为字符串:
print("10" + 1) -->11
print(10 .. 20) -->1020
在Lua中,..是字符串连接操作符,当直接在一个数字后面输入它的时候,必须要用一个空格来分隔它们,否则,Lua会将第一个点理解为一个小数点。除此,Lua还提供了数字与字符串之间显示转换的函数,比如:tonumber和tostring。在Lua 5.1中,还可以在字符串前面放置操作符#来获得该字符串的长度:
a = "hello"
print(#a) -->5
五、table(表)
table类型实现了关联数组(associative array)。关联数组是一种具有特殊索引方式的数组,类似于STL中的map。在这里,不仅可以通过整数来索引它,还可以使用字符串或其它类型的值(除了nil)来索引它。table没有固定大小,可以动态地添加任意数量的元素到一个table中。table是Lua中主要的(事实上也是仅有的)数据结构机制,具有强大的功能。基于table,可以以一种简单、统一和高效的方式来表示普通数组、符号表(symbol table)、集合、记录、队列和其它数据结构。Lua也是通过table来表示模块(module)、包(package)和对象(object)的,比如:当输入io.read的时候,其含义是io模块中的read函数,对于Lua而言,这表示使用字符串read作为key来索引table io。
在Lua中,table既不是值也不是变量,而是对象。可以将一个table想象成一种动态分配的对象,程序仅持有一个对它们的引用或指针,Lua不会暗中产生table副本或创建新的table。table的创建是通过构造表达式完成的,最简单的构造表达式是{}:
a = {} --创建一个table,并将它的引用存储到a
table永远是匿名的,一个持有table的变量与table自身之间没有固定的关联性,当一个程序再也没有对一个table的引用时,Lua的垃圾收集器(garbage collector)最终会删除该table,并复用其内存:
a["x"] = 10 --新条目,key="x", value=10
a[20] = "hello" --新条目,key=20, value="hello"
b = a --b与a引用了同一个table
a = nil --现在只有b还在引用table
b = nil --再也没有对table的引用了,Lua会回收其内存
与全局变量类似,当table的某个元素没有初始化时,其value为nil,将nil赋予table的某个元素来删除该元素。这种相似性的缘由是因为Lua正是将全局变量存储在一个普通table中。
Lua对于诸如a["name"]的写法提供了一种更简便的语法糖(syntactic sugar),可以直接输入a.name。需要注意的是:a.x和a[x]不是一回事,前者表示a["x"],表示以字符串"x"来索引table,而后者是以变量x的值来索引table,比如:
a = {}
x = "y"
a[x] = 10 --将10放入字段“y”
print(a[x]) -->10
print(a.x) -->nil
虽然可以用任何值作为一个table的索引,也可以用任何数字作为数组索引的起始值,但就Lua的习惯而言,数组通常以1作为索引的起始值,这不同于C语言的下标从0开始的习惯。
长度操作符#用于返回一个数组或线性表的最后一个索引值或其大小,比如:
--打印a中所有元素
for i=1, #a do
print(a[i])
end
对于长度操作符Lua中的习惯用法:
print(a[#a]) --打印列表a的最后一个值
a[#a] = nil --删除最后一个值
a[#a+!] = v --将v添加到列表末尾
对于下面数组大小是多少呢:
a = {}
a[10000] = 1
大小是0而不是10000,这是因为数组也是一个table,而table中所有未初始化的元素的索引结果都是nil。Lua将nil作为界定数组结尾的标志,当一个数组有空隙(Hole)时,即中间含有nil时,长度操作符会认为这些nil元素就是结尾标记,因此,应该避免对含有空隙的数组使用长度操作符。当然,可以使用函数table.maxn来返回一个table的最大正索引数:
print(table.maxn[a]) -->10000
六、function(函数)
在Lua中,函数是作为第一类值来看待的,即函数可以存储在变量中,可以通过参数传递给其它函数,还可以作为其它函数的返回值。这种特性使语言具有了极大的灵活性。
Lua既可以调用以自身Lua语言编写的函数,又可以调用以C语言编写的函数。Lua所有的标准库都是用C语言写的,标准库中包括对字符串的操作、table的操作、I/O、操作系统的功能调用、数学函数和调试函数。
七、userdata(自定义类型)
由于userdata类型可以将任意的C语言数据存储到Lua变量中,所以这种类型没有太多的预定义操作,只能进行赋值和相等性测试。userdata用于表示一种由应用程序或C语言库所创建的新类型,例如标准的I/O库就用userdata来表示文件。
八、thread(线程)
后面系列会详细分析这种类型,并介绍协程(coroutine)。
阅读(3806) | 评论(1) | 转发(0) |