类型与值

  1. nil(空)
  2. boolean(布尔)
  3. number(数字)
  4. string(字符串)
  5. table
  6. function(函数)
  7. userdata(自定义类型)和 thread(线程)

    Lua是一种动态类型的语言。在语言中没有类型定义的语法,每个值都“携带”了它自身的类型信息。

  函数type可根据一个值返回其类型名称。type函数总是返回一个字符串

  1. print(type("Hello wold")) -- 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

  变量没有预定义的类型,任何变量都可以包含任何类型的值

  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. a(type(a)) -- function

  

  • nil(空)

  1. “无效值“
  2. nil赋予一个全局变量等同于删除它。

  

  • boolean(布尔)

  1. 有两个可选值:falsetrue
  2. 然后boolean却不是一个条件值的唯一表示方式。
  3. Lua中任何值都可以表示一个条件。Lua将值falsenil视为“假”,而除此之外的其他值视为“真”。
  4. 请注意,Lua在条件测试中,将数字零和空字符串也都视为“真”。

  

  • number(数字)

  number类型用于表示实数。Lua没有整数类型。Lua中的数字可以表示任何32位整数,而不会产生四舍五入的错误。

以下是一些合法的数字常量:

  1. 4 0.4 4.57e-3 0.3e12 5e+20

  

  • string(字符串)

  1. 不可变性。
  2. 需要以一对匹配的单引号或双引号来界定:
  3. a = "a line"
  4. b = 'another line'

    可以包含类似于C语言中的转义序列

转义符说明
\a响铃
\b退格
\f提供表格
\n换行
\r回车
\t水平tab
\v垂直tab
\反斜杠
\"双引号
\'单引号

    另外,还可以用一对匹配的双方括号来界定一个字母字符串,就像写“块注释”那样。以这种形式书写的字符串可以延伸多行,Lua不会解释其中的转义序列。

  1. 例如:
  2. page = [[
  3. <html>
  4. <head>
  5. <title>An HTML Page</title>
  6. </head>
  7. <body>
  8. <a href="http://www.lua.org">Lua</a>
  9. </body>
  10. </html>
  11. ]]
  12. write(page)

    有时字符串中可能需要包含这样的内容:a=b[c[i]]。或者,可能需要包含已经被注释掉的代码。

  为了应付这种情况,需要在两个左方括号间加上任意数量的等号,就像[===[。经过这样修改后,字面字符串只有在遇到一个内嵌有相同数量等号的双右方括号时才会结束(就前例而言,即]===])。如果一组左右方括号中的等号数量不等,那么Lua会忽略它。通过选择适当数量的等号,就可以在不加转义的情况下,直接嵌入任意的字符串内容了。

  这套机制同样适用于注释。例如,以“—[=[”开始的一个块注释将延伸至“]=]”结束。如此便简化了注释那些“已经包含了注释块”的代码。

  

  Lua提供了运行时的数字与字符串的自动转换。  

  1、在一个字符串上应用算术操作时,Lua会尝试将这个字符串转换成一个数字:

  1. print("10" + 1) -- 11
  2. print("10 + 1") -- 10 + 1
  3. print("-5.3e-10" * "2") -- -1.06e-09
  4. print("hello" + 1) -- 错误(不能转换“hello”)
  5. 10=="10" -- false
显式地将一个字符串转换成数字,可以使用函数tonumber。当这个字符串的内容不能表示一个正确的数字时,tonumber将返回nil

    2、相反,在Lua期望一个字符串但却得到一个数字时,它也会将数字转换成字符串

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

  在Lua中,“..”是字符串连接操作符。当直接在一个数字后面输入它的时候,必须要用一个空格来分隔它们。不然,Lua会将第一个点理解为一个小数点。

  1. print(tostring(10)=="10") -- true

  tostring函数可将一个数字转换成字符串

    3、在Lua 5.1中,可以在字符串前放置操作符“#”来获取该字符串的长度

  1. a = "hello"
  2. print(#a) -- 5
  3. print(#"good\0bye") -- 8

  

  • table

  table类型实现了“关联数组”。“关联数组”是一种具有特殊索引方式的数组。不仅可以通过整数来索引它,还可以使用字符串或其他类型的值(除了nil)来索引它。

  table没有固定的大小,可以动态地添加任意数量的元素到一个table中。

  table是Lua中主要的(事实上也是仅有的)数据结构机制,具有强大的功能。

  在Lua中,table既不是“值”也不是“变量”,而是“对象”。

  table的创建是通过“构造表达式”完成的,最简单的构造表达式就是{ }

  1. a = { } -- 创建一个table,并将它的引用存储到a
  2. k = "x"
  3. a[k] = 10 -- 新条目,key = "x", value = 10
  4. a[20] = "great" -- 新条目,key = 20, value = "great"
  5. print(a["x"]) -- 10
  6. k = 20
  7. print(a[k]) -- great"
  8. a["x"] = a["x"] + 1 -- 递增条目"x"
  9. print(a["x"]) -- 11

  table永远是“匿名的”,一个持有table的变量与table自身之间没有固定的关联性。

  1. a = { }
  2. a["x"] = 10
  3. b = a -- ba引用了同一个table
  4. print(b["x"]) -- 10
  5. b["x"] = 20
  6. print(a["x"]) -- 20
  7. a = nil -- 现在只有b还在引用table
  8. b = nil -- 再也没有对table的引用了
  9. -- 当一个程序再也没有对一个table的引用时,Lua的垃圾收集器最终会删除该table,并复用它的内存。

  所有table都可以用不同类型的索引来访问value(值),当需要容纳新条目时,table会自动增长。

  1. a = { }
  2. -- 创建1000个新条目
  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 该元素没有初始化
  8. -- 可以将nil赋予table的某个元素来删除该元素。

  Lua对于诸如a["name"]的写法提供了一种更简便的“语法糖(syntactic sugar)”,可以直接输入a.name

  1. a.x = 10 -- 等同于a["x"] = 10
  2. print(a.x) -- 等同于print(a["x"])
  3. print(a.y) -- 等同于print(a["y"])
  4. -- 对于Lua来说,这两种形式是等价的,可供自由选择使用。
  5. a.x -- 等同于a["x"]
  6. a[x] -- 以变量x的值来索引table
  7. ----------
  8. a = { }
  9. x = "y"
  10. a[x] = 10 -- 10放入字段“y
  11. print(a[x]) -- 10 字段“y”的值
  12. print(a.x) -- nil 字段“x”(未定义)的值
  13. print(a.y) -- 10 字段“y”的值

  若要表示一个传统的数组或线性表,只需以整数作为key来使用table即可。这里不需要(也没有必要)声明一个大小值,直接初始化元素就可以了

  1. -- 读取10行内容,并存储到一个table
  2. a = { }
  3. for i=1,10 do
  4. a[i] = io.read()
  5. end

  虽然可以用任何值作为一个table的索引,也可以用任何数字作为数组索引的起始值。但就Lua的习惯而言,数组通常以1作为索引的起始值。并且还有不少机制依赖于这个惯例。

  在Lua5.1中,长度操作符“#”用于返回一个数组或线性表的最后一个索引值(或为其大小)。

  1. for i=1,#a do
  2. print(a[i])
  3. end
  4. print(a[#a]) -- 打印列表a的最后一个值
  5. a[#a] = nil -- 删除最后一个值
  6. a[#a+1] = v -- v添加到列表末尾
  7. -- 读取一个文件的前10
  8. a = { }
  9. for i=1,10 do
  10. a[#a+1] = io.read()
  11. end

  当对索引的实际类型不是很确定时,可以明确地使用一个显式转换

  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

  

  • function(函数)

  Lua既可以调用以自身Lua语言编写的函数,又可以调用以C语言编写的函数。Lua所有的标准库都是用C语言写的,标准库中包括对字符串的操作、table的操作、I/O、操作系统的功能调用、数学函数和调试函数。同样,应用程序也可以用C语言来定义其他函数。

  1. function function_name( )
  2. -- body
  3. end

  

  • userdata(自定义类型)和 thread(线程)

  由于userdata类型可以将任意的C语言数据存储到Lua变量中。在Lua中,这种类型没有太多的预定义操作,只能进行赋值和相等性测试。userdata用于表示一种由应用程序或C语言库所创建的新类型,例如标准的I/O库就用userdata来表示文件。稍后将在CAPI中详细讨论这种类型。

?