Lua的类型和值
(一)基础介绍
Lua是一种动态类型的语言,变量不需要做定义。Lua中有八种类型,分别是
nil -- 空 boolean -- 布尔 number -- 数字 string -- 字符串 userdata -- 自定义 function -- 函数 thread -- 线程 table -- 表
用type()方法可以识别变量的类型。
1 print(type(nil)) --> nil 2 print(type(true)) --> boolean 3 print(type(1314)) --> number 4 print(type("hello world")) --> string 5 print(type(print)) --> function 6 print(type(type(a))) --> string,type方法返回的是一个string类型的值
变量中不存在预定义,每个变量都可能成为任何一种类型。接下来看下面的例子:
1 print(type(a)) --> nil (a没有初始化) 2 a = 10 3 print(type(a)) --> number 4 a = "a string!!" 5 print(type(a)) --> string 6 a = print 7 print(type(a)) --> function
在上述例子中,变量a在不同类型中切换并不会报错,可是不建议这样使用,会造成混乱。不过有一种特殊情况,即为nil。在Lua中把一个变量赋值为nil时相当于删除该变量。另外由最后两行可得知,在Lua中function实际上也是变量,这个接下来会详细介绍。
(二)nil
一个全局变量在第一次赋值前的默认值就是nil。Lua将nil用于标识"无效值"的情况。
1 local a = {} 2 print(a == nil) --> false
这是笔者最近踩到的一个小坑,在Lua中空的table并不等于nil,被自己蠢哭了。。。
(三)boolean
boolean中有两个可选值:true和false。要特别注意的是,在Lua中只有false和nil是"假",除此之外其余都为"真",所以Lua认为0和空字符串也为真,这和其他语言是有区别的。
(四)number
number类型有两种内部表现形式:整数和浮点数。至于什么时候用哪种内部形式,Lua有明确的规则,同时按需内部作自动转换(参见http://cloudwu.github.io/lua53doc/manual.html#3.4.3)。因此程序员在多数情况下可以选择忽略整数和浮点数之间的差异。
(五)string
Lua中的string是指"字符的序列"。在Lua中可以使用但因行或者双引号表示字符串,在实际开发过程中选一种统一使用即可。
1 a = ‘hello world‘ 2 b = "goodbye world"
当字符串是多行存在时,可以使用"[[]]"符号来界定一个多行字符串,同时,Lua不会解释其中的转义序列。
Lua的字符串是不可改变的。请看下面几行代码:
1 a = "hello world" 2 print(a) --> "hello world" 3 a = "goodbye world" 4 print(a) --> "goodbye world"
可能会有朋友用这种例子来证明字符串是可改变的。清注意,上面的例子中a只是"hello world"这个字符串对象的引用,而下一个赋值语句只是改变了变量a的引用,并没有改变"hello world"本身。
和其他对象一样,Lua自动进行内存分配和释放。
在运行过程中,Lua会自动在string和number之间进行类型转换,至于是string转换成number还是number转换成string依赖于具体操作。当它们之间使用算数运算符操作时,string转化为number
1 print("10" + 1) --> 11 2 print("10 + 1") --> 10 + 1 3 print("5" * "2") --> -10 4 print("hello" + 1) -- ERROR (cannot convert "hello")
当它们之间使用string的相关操作时,number会转化成string,如字符串的连接操作
1 print(10 .. 20) --> 1020
(六)table
table是Lua中一种很强大的类型,与C语言不同的是,table不仅可以通过整数来索引它,还可以使用字符串或其他类型的值(除了nil)来索引它。此外,table没有固定大小,可以动态地添加任意元素到一个table中。(PS:事实上并不推荐table的动态添加,Lua作者有文章提到table的动态添加会降低代码效率,http://www.lua.org/gems/sample.pdf)
在Lua中,table既不是值也不是变量,而是对象。可以将table想象成一种动态分配的对象,程序中仅仅有一个队他们的引用(指针)。table的创建是通过"构造表达式"的完成,最简单的构造函数表达式就是{}。
table是匿名的,一个引用table的变量于table没有固定的关联性。并且当一个table不被任何变量所引用时,会启动垃圾回收机制将它删除,并释放内存。
当table没有初始化时,他的内容就是nil,另外还可以像全局变量一样,将nil赋予table的某个变量来删除该元素。在Lua中,对于a["name"]这种形式的写法提供了一种更简便的写法,就是
a.name
这种写法虽然简便,却很容易给新手程序员带来困惑。实际上,a["x"]表示以字符串"x"来索引table;而a[x]是以x的值来索引table。以下代码可解释:
1 local a = {} 2 x = "y" 3 a[x] = 10 4 print(a[x]) -->10 相当于a["y"] 5 print(a.x) -->nil 相当于a["x"] 6 print(a.y) -->10 相当于a["y"]
在Lua5.1中,长操作符"#"用于返回一个数组或线性表的最后一个索引值。在实际项目中我们经常利用该操作符来获取数组或线性表的长度。但是该操作符的使用是有坑的,比如下面这段代码:
1 local a = {} 2 a[1000] = 1 3 print(#a)
在Lua中,对于所有未初始化的元素索引的结果都是nil。Lua将nil作为界定数组的标志。当一个数组有"空隙"时,即中间含有nil时,长度操作符会认为这些nil元素解释结尾标志。因为a[1]=nil,所以,对于上述代码的输出应该是0。所以,在处理table的时候,需要考虑这个问题。
(七)function
Lua中的函数是第一类值,即既能作为参数和返回值,又能赋值给其他变量。Lua既可以调用自身Lua语言编写的函数,又可以调用以C语言编写的函数。Lua所有的标准库都是C语言实现的,包括string库、table库、I/O库、OS库、算术库、debug库。
(八)userdata和thread
userdata顾名思义是用户自定义数据的意思。它是用于标识一种由应用程序或C语言库所创建新类型。由于userdata类型可以将任意的C语言数据存储到Lua变量中。在Lua中userdata的预定义操作只有赋值和相等性比较。
thread主要用于协同程序,以后会详细讲解。