本文是《Programming in Lua 3rd》读书笔记。
Chunks
一个 Chunk 就是一组被执行的语句,例如一个文件或者交互模式下的一行。
标识符(identifiers)
我们应该避免使用以 _ 开头并跟上一个或者多个大写字母的字符串来作标识符,它们被保留作特殊的用途(例如:_VERSION)。
注释
单行注释使用
--
--[[ 和 --]]
类型简介
Lua 存在的数据类型包括:
1.nil。此类型只有一个值 nil。用于表示“空”值。全局变量默认为 nil,删除一个已经赋值的全局变量只需要将其赋值为 nil(对比 JavaScript,赋值 null 并不能完全删除对象的属性,属性还存在,值为 null)
2.boolean。此类型有两个值 true 和 false。在 Lua 中,false 和 nil 都表示条件假,其他值都表示条件真(区别于 C/C++ 等语言的是,0 是真)
3.number。双精浮点数(IEEE 754 标准),Lua 没有整数类型
4.string。你可以保存任意的二进制数据到字符串中(包括 0)。字符串中的字符是不可以改变的(需要改变时,你只能创建一个新的字符串)。获取字符串的长度,可以使用 # 操作符(长度操作符)。例如:print(#”hello”)。字符串可以使用单引号,也可以使用双引号包裹,对于多行的字符串还可以使用 [[ 和 ]] 包裹。字符串中可以使用转义字符,例如 \n \r 等。使用 [[ 和 ]] 包裹的字符串中的转义字符不会被转义
5.userdata。用于保存任意的 C 数据。userdata 只能支持赋值操作和比较测试
6.function。函数是第一类值(first-class value),我们能够像使用其他变量一样的使用函数(函数能够保存在变量中,可以作为参数传递给函数)
7.thread。区别于我们常常说的系统级线程
8.table。被实现为关联数组(associative arrays),可以通过任何值来进行索引(nil 除外)。和全局变量一样,table 中未赋值的域为 nil,删除一个域只需要将其赋值为 nil(实际上,全局变量就是被放置在一个 table 中)
type 函数用于返回值的类型:
print(type("Hello World")) --> string print(type(10.4*3)) --> number print(type(print)) --> function print(type(type(X))) --> string
在 Lua 中,任何的变量都可以保存任何的值。
table 使用简介
使用构造表达式可以创建一个 table:
-- 创建一个空的 table a = {} -- 创建并初始化一个 table,这里 -- days[1] == "Sunday" -- days[2] == "Monday" -- ... days = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" } -- 创建并初始化一个 table,这里 -- a["x"] == 10 -- a["y"] == 20 a = { x = 10, y = 20 }
使用 [] 操作符访问 table 的域:
a = {} k = "x" a[k] = 10 a["x"] = 20 print(a["y"]) --> nil a.x = 30
注意,a.name 的语法等价于 a["name"]。
table 可以用于表示数组,这时候索引为整数,并且从 1(而非 0)开始,例如:
a = { 'a', 'b' } a[1] == 'a' a[2] == 'b'
长度操作符可以获取 table 数组部分的长度:
a = {} a[1] = 1 a[2] = 2 print(#a) --> 2 a.a = 1 a.b = 2 print(#a) --> 2 a = {} a.a = 1 a.b = 2 print(#a) --> 0
表达式
算术操作符
1.+(加)
2.-(减)
3.*(乘)
4./(除)
5.^(幂)
6.%(取模)
任何算术操作符都试图将操作数转换为数值类型,例如:
print(10 + '1') --> 11
关系操作符
1.<(小于)
2.>(大于)
3.<=(小于等于)
4.>=(大于等于)
5.==(等于)
6.~=(不等于)
两个不同类型的值是不相等的,例如:
nil ~= false
table、userdata 类型是通过引用进行比较的,例如:
a = {}; a.x = 1; a.y = 0 b = {}; b.x = 1; b.y = 0 c = a
这里 a 和 c 引用一个相同的对象,因此 a == c,但是 a ~= b(即便 a、b 内容相同)。
逻辑操作符
1.and
2.or
3.not
逻辑操作符有返回值。对于 and 操作来说,如果第一个操作数为 false 时返回此操作数,否则返回第二个操作数。对于 or 操作来说,如果第一个操作数不为 false 时返回此操作数,否则返回第二个操作数。
连接操作符
字符串连接可以使用连接操作符 “..”,例如:
print("Hello " .. "World")
print("number: " .. 1)
语句
多赋值(multiple assignment)支持,例如:
a, b = 1, 2 print(a) --> 1 print(b) --> 2
x, y = 1, 2 x, y = y, x print(x) --> 2 print(y) --> 1
j = 10 -- 全局变量 j local i = 10 -- 局部变量 i
局部变量的作用域限制于他们声明的块(block)。块(block)包括:
1.控制结构的主体部分
2.函数体
3.chunk
4.do-end
范例:
if true then local x = 20 print(x) --> 20 end print(x) --> nil
do local x = 20 print(x) --> 20 end print(x) --> nil
local foo = foo
1.避免某些类型的全局变量被修改
2.提高访问速度
控制结构
if then elseif else
if a < 0 then a = 0 end if a < b then return a else return b end if op == '+' then r = a + b elseif op == '-' then r = a - b elseif op == '*' then r = a * b elseif op == '/' then r = a / b else error('invalid operation') end
Lua 中没有 switch 语句。
while
local i = 1 while a[i] do print(a[i]) i = i + 1 end
repeat
repeat line = io.read() until line ~= '' print(line)
区别于 while,repeat 会先执行循环体,然后判断测试条件。
数值型 for(numeric for)
for 有两种:
数值型 for(numeric for)
1.泛型 for(generic for)
2.数值型 for 的语法如下:
for var = exp1, exp2, exp3 do <something> end
-- 输出 1 2 3 for i = 1, 3 do print(i) end
有一些需要注意的地方:
1.for 中的 exp1、exp2、exp3 只会被计算一次值,例如:
for i = 1, f(x) do print(i) end
2.控制变量 var 只是一个局部变量
3.不要尝试去修改控制变量 var 的值(结果是未知的)
泛型 for
泛型 for 通过一个迭代器函数来实现遍历,例如:
for k, v in pairs(t) do print(k, v) end
这里的 pairs 就是一个迭代器函数,此 for 循环遍历 table t,每次获取到的 key 保存在变量 k 中,获取到的 value 保存在变量 v 中。除了 pairs 还有其他的迭代器可以用:
1.io.lines 可用于迭代文件中的行
2.ipairs 可用于迭代 table 的数组部分
我们还可以自己编写迭代器。
break、return、goto
break 语句用于跳出一个循环(for、repeat、while)。
return 语句用于为函数返回结果。在 Lua 中,return 语句必须是一个块的最后一条语句,看一个例子:
function foo() -- 语法错误 return local i = 1 end
有时候,我们出于某些原因(例如为了 debug),我们需要在一个函数中插入一个 return 语句,这时候可以这么做:
function foo() -- ... do return end -- ... end
goto 语句用于在函数中跳转。goto 语句可以让执行跳转到特定的标签(label)处,例如:
goto quit print('come on') ::quit:: print('quit')
这里输出 quit。正如我们看到的,标签的写法为 ::name::。goto 跳转也是存在限制的:
1.不允许跳转到一个块中去
2.不允许跳转到函数之外去
3.不允许跳入局部变量的作用域中
对于第三点,看一个例子:
goto quit local a ::quit:: print('quit')
这里,会出现语法错误(jumps into the scope of local 'a')。但是,有一个细节需要注意,我们先修改上面的例子:
goto quit local a ::quit::
执行成功,没有语法错误。这是因为局部变量的作用域结束于变量定义的块的最后一个非 void 语句,而标签被认为是一个 void 语句,对于上面的例子来说,a 的作用域在 ::quit:: 之前就结束了,因此 goto quit 并没有跳入局部变量 a 的作用域中。
利用 goto 可以比较方便的编写状态机,例如(s1、s2 为状态):
::s1:: do local c = io.read(1) if c == '0' then goto s2 elseif c == nil then print'ok'; return else goto s1 end end ::s2:: do local c = io.read(1) if c == '0' then goto s1 elseif c == nil then print'not ok'; return else goto s2 end end goto s1
本文向大家介绍Lua极简入门指南(一):函数篇,包括了Lua极简入门指南(一):函数篇的使用技巧和注意事项,需要的朋友参考一下 Lua 和其他很多语言一样,函数调用时参数列表被包裹在括号中: 特别的情况是,如果函数调用时只有一个参数,并且此参数为字符串 literal(字面量)或者 table 构造器(constructor)时,包裹参数的括号可以省略: Lua 为面向对象的调用提供了特殊的语法:
本文向大家介绍jQuery入门基础知识学习指南,包括了jQuery入门基础知识学习指南的使用技巧和注意事项,需要的朋友参考一下 打开一个网页,如果 HTML 没有完全加载完毕,就去操作页面中元素是不安全的,但是监测 HTML 是否加载完毕呢?jQuery 提供了一个 $(document).ready() 方法,任何 ready 中的代码在 HTML 完全加载完成后才会被执行。 此外,它还有一个简
本文向大家介绍Lua极简入门指南:全局变量,包括了Lua极简入门指南:全局变量的使用技巧和注意事项,需要的朋友参考一下 全局环境 Lua 把全局变量放在一个 table _G 中,这个 table 被叫做全局环境(global environment)。打印所有的全局变量名: _ENV(Lua 5.2 开始支持) 对于一个 free name(名字没有绑定任何声明)var 实际上会被转换为 _EN
(1) 变量 赋值 赋值是改变一个变量的值和改变表域的最基本的方法。Lua 中的变量没有类型,只管赋值即可。比如在 Lua 命令行下输入: end_of_world = "death" print(end_of_world) end_of_world = 2012 print(end_of_world) 上面这四行代码 Lua 不会报错,而会输出: death 2012 局部变量
本文向大家介绍JavaScript极简入门教程(一):基础篇,包括了JavaScript极简入门教程(一):基础篇的使用技巧和注意事项,需要的朋友参考一下 阅读本文需要有其他语言的编程经验。 开始学习之前 大多数的编程语言都存在好的部分和差的部分。本文只讲述 JavaScript 中好的部分,这是因为: 1.仅仅学习好的部分能够缩短学习时间 2.编写的代码更加健壮 3.编写的代码更加易读 4.编写
本文向大家介绍ThinkPHP3.1基础知识快速入门,包括了ThinkPHP3.1基础知识快速入门的使用技巧和注意事项,需要的朋友参考一下 在当今众多的MVC框架中,ThinkPHP是一个快速、简单的基于MVC和面向对象的轻量级PHP开发框架,其遵循Apache2开源协议发布,自从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,尤其注重开发体验及易用性,并且拥有众多的原创功