关键字
and, break, do, else, elseif, end, false, for, function, if, in, local, nil, not, or, repeat, return, then, true, until, while
数据类型
8个基本类型: nil, boolean, number, string, userdata, function, thread, table
数据类型 | 描述 |
---|---|
nil | 这个最简单, 只有值nil属于该类, 表示一个无效值(在条件表达式中相当于false). |
boolean | 包含两个值: false和true. |
number | 表示双精度类型的实浮点数 |
string | 字符串由一对双引号或单引号来表示 |
function | 由 C 或 Lua 编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线路, 用于执行协同程序 |
table | Lua 中的表(table)其实是一个”关联数组”(associative arrays), 数组的索引可以是数字, 字符串或表类型.在 Lua 里, table 的创建是通过”构造表达式”来完成, 最简单构造表达式是{}, 用来创建一个空表. |
nil 作比较时应该加上双引号 “:
> type(X)
nil
> type(X)==nil
false
> type(X)=="nil"
true
>
string(字符串)
字符串由一对双引号或单引号来表示.
string1 = "this is string1"
string2 = 'this is string2'
可以用 2 个方括号 “[[]]” 来表示”一块”字符串.
html = [[
<html>
<head></head>
<body>
<a href="http://www.runoob.com/">菜鸟教程</a>
</body>
</html>
]]
print(html)
在对一个数字字符串上进行算术操作时, Lua 会尝试将这个数字字符串转成一个数字.
字符串连接使用的是 .. .
使用 # 来计算字符串的长度, 放在字符串前面.
table(表)
在lua里, table的创建是通过”构造表达式”来完成的, 最简单的构造表达式是{}, 用来创建一个空表.
Lua中的表其实是一个”关联数组”(associative arrays), 数组的索引可以是数字或者字符串.
不同于其他语言的数组把 0 作为数组的初始索引, 在 Lua 里表的默认初始索引一般以 1 开始.
table 不会固定长度大小, 有新数据添加时 table 长度会自动增长, 没初始的 table 都是 nil.
Table操作
table.concat (table [, sep [, start [, end]]]), table.insert (table, [pos,] value), table.remove (table [, pos]), table.sort (table [, comp])
function(函数)
在Lua中, 函数是被看作是”第一类值(First-Class Value)”, 函数可以存在变量里.
在函数参数列表中使用三点 … 表示函数有可变的参数.
function add(...)
local s = 0
for i, v in ipairs{...} do --> {...} 表示一个由所有变长参数构成的数组
s = s + v
end
return s
end
print(add(3,4,5,6,7)) --->25
function 可以以匿名函数(anonymous function)的方式通过参数传递:
function testFun(tab, fun)
for k, v in pairs(tab) do
print(fun(k, v))
end
end
tab={key1="val1",key2="val2"};
testFun(tab,
function(key,val)--匿名函数
return key.."="..val;
end
);
通过select(“#”, …)获取参数的数量
function average(...)
result = 0
local arg = {...}
for i, v in ipairs(arg) do
result = result + v
end
print("总传入 " .. select("#", ...) .. "个参数")
return result / select("#", ...)
end
print("平均值为", average(10, 3, 4, 5, 7, 8))
- select(‘#’, …) 返回可变参数的长度
- select(n, …) 用于访问 n 到 select(‘#’,…) 的参数
do
function foo(...)
for i = 1, select('#', ...) do -->获取参数总数
local arg = select(i, ...); -->读取参数
print("arg", arg);
end
end
foo(1, 2, 3, 4);
end
thread(线程)
在 Lua 里, 最主要的线程是协同程序(coroutine).它跟线程(thread)差不多, 拥有自己独立的栈, 局部变量和指令指针, 可以跟其他协同程序共享全局变量和其他大部分东西.
userdata(自定义类型)
userdata 是一种用户自定义数据, 用于表示一种由应用程序或 C/C++ 语言库所创建的类型, 可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用.
变量
Lua 变量有三种类型: 全局变量, 局部变量, 表中的域.
Lua 中的变量全是全局变量, 那怕是语句块或是函数里, 除非用 local 显式声明为局部变量.
变量的默认值均为 nil.
pairs可以遍历表中所有的key, 并且除了迭代器本身以及遍历表本身还可以返回nil;
ipairs则不能返回nil,只能返回数字0, 如果遇到nil则退出.
tbl = {"alpha", "beta", [3] = "uno", ["two"] = "dos"}
for i,v in ipairs(tbl) do --输出前三个
print( tbl[i] )
end
for i,v in pairs(tbl) do --全部输出
print( tbl[i] )
end
运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 其他运算符
算术运算符
操作符 | 描述 | 实例 |
---|---|---|
+ | 加法 | A + B 输出结果 30 |
- | 减法 | A - B 输出结果 -10 |
* | 乘法 | A * B 输出结果 200 |
/ | 除法 | B / A w输出结果 2 |
% | 取余 | B % A 输出结果 0 |
^ | 乘幂 | A^2 输出结果 100 |
- | 负号 | -A 输出结果 -10 |
关系运算符
操作符 | 描述 | 实例 |
---|---|---|
== | 等于, 检测两个值是否相等, 相等返回 true, 否则返回 false | (A == B) 为 false. |
~= | 不等于, 检测两个值是否相等, 相等返回 false, 否则返回 true | (A ~= B) 为 true. |
> | 大于, 如果左边的值大于右边的值, 返回 true, 否则返回 false | (A > B) 为 false. |
< | 小于, 如果左边的值大于右边的值, 返回 false, 否则返回 true | (A < B) 为 true. |
>= | 大于等于, 如果左边的值大于等于右边的值, 返回 true, 否则返回 false | (A >= B) 返回 false. |
<= | 小于等于, 如果左边的值小于等于右边的值, 返回 true, 否则返回 false | (A <= B) 返回 true. |
逻辑运算符
操作符 | 描述 | 实例 |
---|---|---|
and | 逻辑与操作符. 若 A 为 false, 则返回 A, 否则返回 B. | (A and B) 为 false. |
or | 逻辑或操作符. 若 A 为 true, 则返回 A, 否则返回 B. | (A or B) 为 true. |
not | 逻辑非操作符.与逻辑运算结果相反, 如果条件为 true, 逻辑非为 false. | not(A and B) 为 true. |
其他运算符
操作符 | 描述 | 实例 |
---|---|---|
.. | 连接两个字符串 | a..b , 其中 a 为 “Hello “ , b 为 “World”, 输出结果为 “Hello World”. |
# | 一元运算符, 返回字符串或表的长度. | #”Hello” 返回 5 |
运算符优先级
^
not - (unary)
* /
+ -
..
< > <= >= ~= ==
and
or
除了 ^ 和 .. 外所有的二元运算符都是左连接的.
a+i < b/2+1 <--> (a+i) < ((b/2)+1)
5+x^2*8 <--> 5+((x^2)*8)
a < y and y <= z <--> (a < y) and (y <= z)
-x^2 <--> -(x^2)
x^y^z <--> x^(y^z)
迭代器
无状态的迭代器
无状态的迭代器是指不保留任何状态的迭代器, 因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价.
每一次迭代, 迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用, 一个无状态的迭代器只利用这两个值可以获取下一个元素.
这种无状态迭代器的典型的简单的例子是 ipairs, 它遍历数组的每一个元素.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,3,0
do
print(i,n)
end
迭代的状态包括被遍历的表(循环过程中不会改变的状态常量)和当前的索引下标(控制变量), ipairs 和迭代函数都很简单, 我们在 Lua 中可以这样实现:
function iter (a, i)
i = i + 1
local v = a[i]
if v then
return i, v
end
end
function ipairs (a)
return iter, a, 0
end
当 Lua 调用 ipairs(a) 开始循环时, 他获取三个值: 迭代函数 iter, 状态常量 a, 控制变量初始值 0;然后 Lua 调用 iter(a,0) 返回 1, a[1](除非 a[1]=nil);第二次迭代调用 iter(a,1) 返回 2, a[2]……直到第一个 nil 元素.
多状态的迭代器
很多情况下, 迭代器需要保存多个状态信息而不是简单的状态常量和控制变量, 最简单的方法是使用闭包, 还有一种方法就是将所有的状态信息封装到 table 内, 将 table 作为迭代器的状态常量, 因为这种情况下可以将所有的信息存放在 table 内, 所以迭代函数通常不需要第二个参数.以下实例我们创建了自己的迭代器:
array = {"Google", "Baidu", "QWant"}
function elementIterator(collection)
local index = 0
local count = #collection
-- 闭包函数
return function ()
index = index + 1
if index <= count
then
-- 返回迭代器的当前原生
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Lua模块与包
require(“<模块名>”) 或 require “<模块名>”
使用require会缓存.
加载机制
搜索的文件路径存放在全局变量package.path
中, 当lua启动后, 会已环境变量 LUA_PATH 的值俩初始化这个环境变量, 如果没有找到这个环境变量, 则使用一个编译时定义的默认路径来初始化.
这个 LUA_PATH 环境变量也可以自定义.
假设现在 package.path 的值是:
D:\Tools\lua\lua\?.lua;D:\Tools\lua\lua\?\init.lua;D:\Tools\lua\?.lua;D:\Tools\lua\?\init.lua;D:\Tools\lua\..\share\lua\5.3\?.lua;D:\Tools\lua\..\share\lua\5.3\?\init.lua;.\?.lua;.\?\init.lua
那么调用require(“module”)时就会尝试打开以上文件目录去搜索.
c包
Lua和C是很容易结合的, 使用 C 为 Lua 写包.
与Lua中写包不同, C包在使用以前必须首先加载并连接, 在大多数系统中最容易的实现方式是通过动态连接库机制.
Lua在一个叫loadlib的函数内提供了所有的动态连接的功能.这个函数有两个参数:库的绝对路径和初始化函数.所以典型的调用的例子如下:
local path = "/usr/local/lua/lib/libluasocket.so"
local f = loadlib(path, "luaopen_socket")
loadlib 函数加载指定的库并且连接到 Lua, 然而它并不打开库(也就是说没有调用初始化函数), 反之他返回初始化函数作为 Lua 的一个函数, 这样我们就可以直接在Lua中调用他.
如果加载动态库或者查找初始化函数时出错, loadlib 将返回 nil 和错误信息.我们可以修改前面一段代码, 使其检测错误然后调用初始化函数:
local path = "/usr/local/lua/lib/libluasocket.so"
-- 或者 path = "C:\\windows\\luasocket.dll", 这是 Window 平台下
local f = assert(loadlib(path, "luaopen_socket"))
f() -- 真正打开库
一般情况下二进制的发布库包含一个与前面代码段相似的 stub 文件, 安装二进制库的时候可以随便放在某个目录, 只需要修改 stub 文件对应二进制库的实际路径即可.
将 stub 文件所在的目录加入到 LUA_PATH, 这样设定后就可以使用 require 函数加载 C 库了.