Chinaunix首页 | 论坛 | 博客
  • 博客访问: 66937
  • 博文数量: 7
  • 博客积分: 450
  • 博客等级: 下士
  • 技术积分: 120
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-10 10:02
文章分类
文章存档

2010年(3)

2009年(1)

2008年(3)

我的朋友

分类: LINUX

2008-03-04 15:15:25

2.类型和值(Types and Values)
Lua是动态类型语言,变量不要类型定义. 变量的值就决定了变量的类型。
Lua中有8个基本类型:nil, boolean, number, string, userdata, function, thread, and table.
type函数可以返回给定值的类型。例如:
  1. print(type("Hello world")) --> string
  2. print(type(10.4*3))        --> number
  3. print(type(print))          --> function
  4. print(type(type))           --> function
  5. print(type(true))           --> boolean
  6. print(type(nil))            --> nil
  7. print(type(type(X)))        --> string
最后这句中,结果肯定是“string”,因为无论X的取值如何,type(type(X))都会返回一个字符串。
变量没有预定义的类型,每一个变量都可能包含任一种类型的值.
  1. print(type(a))   --> nil   (`a' is not initialized)
  2. a = 10
  3. print(type(a))   --> number
  4. a = "a string!!"
  5. print(type(a))   --> string
  6. a = print        -- yes, this is valid!
  7. a(type(a))       --> function
注意上面最后两行,我们可以使用function像使用其他值一样使用(第6章中会作详细说明)。
一般情况下同一变量代表不同类型的值会造成混乱,最好不要用,特殊情况下可以带来便利,比如nil.

2.1 空类型(nil)
Lua中特殊的类型,它的主要作用是让一个变量的值和其它的值区分开。我们已经知道,全局变量在被赋值前,其初始值是nil。给全局变量赋nil可以删除该变量。Lua通过nil来表现一种“无值”的概念。

2.2 布尔型(booleans)
两个取值false和true。但要注意Lua中所有的值都可以作为条件.在控制结构的条件中除了false和nil为假,其他值都为真.所以Lua认为0和空串都是真。这和某些脚本语言是不同的。

2.3 数字型(numbers)
表示实数,Lua中没有整数.一般有个错误的看法CPU运算浮点数比整数慢.事实不是如此,用实数代替整数不会有什么误差(除非数字大于100,000,000,000,000).Lua的numbers可以处理任何长整数不用担心误差。你也可以在编译Lua的时候使用长整型或者单精度符点型代替numbers。这在不支持硬件浮点运算的平台上很有用。Lua可以以科学计数法来表示数字,下面是数字常量的例子:
  1. 4     0.4     4.57e-3     0.3e12     5e+20
2.4 字符串(strings)
string表示字符串,就像很多语言中的string一样,它指一组字符序列。lua 是8位字节,所以字符串可以包含任何数值字符,包括嵌入的0。 这意味着你可以存储任意的2进制数据在一个字符串里.Lua中字符串是不可以修改的(这点和C语言不同),你可以创建一个新的变量存放你要的字符串,比如:
  1. a = "one string"
  2. b = string.gsub(a, "one", "another")  -- 修改部分字符串

  3. print(a)       --> one string
  4. print(b)       --> another string
string和其他对象一样,Lua自动进行内存分配和释放,你不必关心为字符串申请内存空间或释放它的问题。一个string可以只包含一个字母也可以包含一本书,Lua可以高效的处理长字符串,100K或1M的string在Lua中是很常见的。可以使用单引号或者双引号表示字符串

  1. a = "a line"
  2. b = 'another line'
为了风格统一,最好使用一种,除非两种引号嵌套情况.对于字符串中含有引号的情况还可以使用转义符\来表示.Lua中的转义序列有:
 
\a bell
\b back space
\f form feed
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\" double quote
\' single quote
\[ left square bracket
\] right square bracket

例子:

  1. print("one line\nnext line\n\"in quotes\", 'in quotes'")
  2. one line
  3. next line
  4. "in quotes", 'in quotes'
  5. > print('a backslash inside quotes: \'\\\'')
  6. a backslash inside quotes: '\'
  7. > print("a simpler way: '\\'")
  8. a simpler way: '\'

还可以在字符串中使用\ddd(ddd为三位十进制数字)方式表示字母。"alo\n123\"" 和 '\97lo\10\04923"'是相同的。还可以使用[[...]]表示字符串.这种形式的字符串可以包含多行,可以嵌套,不会解释转义序列,如果第一个字符是换行符会被自动忽略掉.这种形式的字符串用来包含一段代码是非常方便的.

  1. page = [[
  2. An HTML Page
  3. >
  4. [[a text between double brackets]]
--注意:上面这行代码在Lua5.0.2版本中是可以执行的,但是在Lua5.1版本中就不行了。

  1. ]]
  2. io.write(page)

运行时,Lua会在string和numbers之间自动进行类型转换,当一个字符串使用算术操作符时,string会被转成数字。

  1. print("10" + 1)           --> 11
  2. print("10 + 1")           --> 10 + 1
  3. print("-5.3e - 10"*"2")   --> -1.06e-09
  4. print("hello" + 1)        -- ERROR (cannot convert "hello")

反过来,当Lua期望一个string而碰到数字时,会将数字转成string。

  1. print(10 .. 20)        --> 1020

(".."在Lua中是字符串连接符,当在一个数字后面写..时必须加上空格防止被解释错(如果不加,Lua会将第一个.解释为小数点,这样就错了)。尽管字符串和数字可以自动转换,两者是不同的,像 10 == "10"这样的比较永远都是错的。如果需要显式将string转成数字可以使用函数tonumber(),如果string不是正确的数字该函数返回nil。

  1. line = io.read()     -- read a line
  2. n = tonumber(line)   -- try to convert it to a number
  3. if n == nil then
  4.   error(line .. " is not a valid number")
  5. else
  6.   print(n*2)
  7. end

反之,可以调用tostring()将数字转成字符串,或者,在一个数字后连接一个空字符串,也可以实现这种转换:

  1. print(tostring(10) == "10")   --> true
  2. print(10 .. "" == "10")       --> true
这种转换始终会有效的。

2.5 表(tables)
Lua 的tables实现了关联数组,关联数组指不仅可以通过数字检索数据,还可以通过别的类型的值检索数据.Lua中除了nil外的类型都可以作为 tables的索引下标.tables可以进行动态内存分配。tables是Lua主要的也是唯一的数据结构,我们可以通过他实现传统数组, 符号表, 集合, 记录(pascal), 队列, 以及其他的数据结构. Lua的包(package)也是使用tables来描述的,io.read意味着调用io包中的read函数,对Lua而言意味着使用字符串read作 为下标访问io表
.
Lua中tables不是变量也不是值,而是对象。如果你 对数组的印象来自于C或者Pascal,就需要你改变一下观念。 你可以把tables当作自动分配的对象,程序中只需要操纵表的引用(指针)即可.Lua中不需要声明表(也无法声明),使用最简单的{}表达式语句即可 创建表
.
  1. a = {}                  -- 创建一个表,并赋值给
  2. a
  3. k = "x"
  4. a[k] = 10               -- 加入一个成员, key="x" and value=10
  5. a[20] = "great"         --加入一个成员,key=20 and value="great"
  6. print(a["x"])           --> 10
  7. k = 20
  8. print(a[k])             --> "great"
  9. a["x"] = a["x"] + 1     -- 改变 "x" 成员的值
  10. print(a["x"])           --> 11
表是匿名的,意味着表和持有表的变量没有必然的关系。
  1. a = {}
  2. a["x"] = 10
  3. b = a          -- b和a引用同一个
  4. table
  5. print(b["x"])  --> 10
  6. b["x"] = 20
  7. print(a["x"])  --> 20
  8. a = nil        -- 现在,只有b引用这个table了
  9. b = nil        -- 现在没有变量再引用这个table
当程序中不再引用表时,这个表将被删除,内存可以重新被利用.表可以使用不同的索引类型存储值。索引大小随着表中元素个数增加而增加。
  1. a = {}         -- empty table
  2. -- create 1000 new entries
  3. for i=1,1000 do a[i] = i*2 end
  4. print(a[9])    --> 18
  5. a["x"] = 10
  6. print(a["x"])  --> 10
  7. print(a["y"])  --> nil
注意最后一行,表对应的域没有被初始化,所以为nil,这和全局变量一样。你也可以通过将某个元素赋值为nil来删除这个元素。实际上,Lua的全局变量存储正是使用表来存储的。更多关于这个问题的讨论见第14章。
可以使用域名作为索引下标访问表中元素,Lua也支持a.name代替a["name"],所以我们可以用更清晰的方式重写上面的例子
:
  1. a.x = 10                    -- same as a["x"] = 10
  2. print(a.x)                  -- same as print(a["x"])
  3. print(a.y)                  -- same as print(a["y"])
两种方式可以混合使用,对于Lua来说,两种方式相同,但对于读者来说单一的风格更易理解。
常见的错误:混淆a.x 和a[x];第一种表示a["x"],即访问域为字符串"x"的表中元素,第二种表示使用变量x作为索引下标访问表中元素。
  1. a = {}
  2. x = "y"
  3. a[x] = 10                 -- put 10 in field "y"
  4. print(a[x])   --> 10      -- value of field "y"
  5. print(a.x)    --> nil     -- value of field "x" (undefined)
  6. print(a.y)    --> 10      -- value of field "y"
只要使用整数作为索引下标就可以表示传统的数组了,不需要指定数组大小:
  1. -- read 10 lines storing them in a table
  2.    a = {}
  3.    for i=1,10 do
  4.      a[i] = io.read()
  5.    end
当遍历数组元素时,第一个没有初始化的元素返回nil,可以用这个当作数组下标的边界标志.可以用下面的代码打印出上个例子读入的行:
  1. -- print the lines
  2.    for i,line in ipairs(a) do
  3.      print(line)
  4.    end
既然可以使用任意值作为表的下标,你可以以任何数字作为数组下标的开始,但是Lua中一般以1开始而不是0(和c语言不同).Lua标准库也是以这个设计的.
有一点需要特别注意,否则你的代码中可能引入很多难以发现的bug.因为我们可以使用任意类型的值作为索引下标,要注意:number 0 和string "0"是不同的,同样strings "+1", "01", and "1"也是不同的
.
  1. i = 10; j = "10"; k = "+10"
  2. a = {}
  3. a[i] = "one value"
  4. a[j] = "another value"
  5. a[k] = "yet another value"
  6. print(a[j])            --> another value
  7. print(a[k])            --> yet another value
  8. print(a[tonumber(j)])  --> one value
  9. print(a[tonumber(k)])  --> one value
当对你检索的类型有疑问时,请使用显示类型转换。

2.6 函数(Functions)
函 数是第一类值(和其他变量相同),意味着函数可以存储在变量中,可以作为函数的参数,也可以作为函数的返回值。这个特性给了语言很大的灵活性:一个程序可 以重新定义函数增加新的功能,或者为了避免运行不可靠代码而删除掉一些函数,另外这个特性在Lua实现面向对象中也起了重要作用。(详细讨论见第16章)
Lua可以调用lua或者C实现的函数,Lua所有标准库都是用C实现的.标准库包括string库,table库,I/O库,OS库,算术库,debug库。

2.7 用户数据和线程(Userdata and Threads)
userdata 可以将C数据存放在Lua变量中,userdata 在Lua中除了赋值和相等比较外没有预定义的操作.userdata 用来描述应用程序或者使用C实现的库创建的新类型.例如:标准I/O库用来描述文件.下面在C API章节中我们将详细讨论。

在第九章讨论协同操作的时候,我们介绍线程。
 
阅读(2852) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Programming in Lua (第三章---表达式)

给主人留下些什么吧!~~