赋值是改变一个变量的值和改变表域的最基本的方法。Lua 中的变量没有类型,只管赋值即可。比如在 Lua 命令行下输入:
end_of_world = "death"
print(end_of_world)
end_of_world = 2012
print(end_of_world)
上面这四行代码 Lua 不会报错,而会输出:
death
2012
使用 local 创建一个局部变量,与全局变量不同,局部变量只在被声明的那个代码块内有效
x = 10
local i = 1 -- 局部变量
while i<=x do
local x = i*2 -- while 中的局部变量
print(x) --> 2, 4, 6, 8, ...
i = i + 1
end
应该尽可能的使用局部变量,有两个好处:
代码块指一个控制结构内,一个函数体,或者一个chunk(变量被声明的那个文件或者文本串)。
我们给block划定一个明确的界限:do..end内的部分。当你想更好的控制局部变量的作用范围的时候这是很有用的。
do
local a2 = 2*a
local d = sqrt(b^2 - 4*a*c)
x1 = (-b + d)/a2
x2 = (-b - d)/a2
end -- scope of 'a2' and 'd' ends here
print(x1, x2)
虽说变量没有类型,但并不是说数据不分类型。Lua 基本数据类型共有八个:nil、boolean、number、string、function、userdata、thread、table。
可以用 type 函数取得表达式的数据类型:
print(type(undefined_var))
print(type(true))
print(type(3.14))
print(type('Hello World'))
print(type(type))
print(type({}))
有几个操作符跟C语言不一样的:
最简单的构造函数是{},用来创建一个空表。可以直接初始化数组:
days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
Lua将"Sunday"初始化days[1](第一个元素索引为1),不推荐数组下标以0开始,否则很多标准库不能使用。
在同一个构造函数中可以数组风格和字典风格进行初始化:
polyline = {color="blue", thickness=2, npoints=4,
{x=0, y=0},
{x=-10, y=0},
{x=-10, y=1},
{x=0, y=1}
}
另外 Lua 还支持多重赋值(还支持函数返回多个值)。也就是说:等号右边的值依次赋值给等号左边的变量。比如:
year, month, day = 2011, 3, 12
print(year, month, day)
reutrn year, month, day -- 多返回值
a, b = f()
于是,交换两个变量值的操作也变得非常简单:
a, b = b, a
name = "peach"
if name == "apple" then
-- body
elseif name == "banana" then
-- body
else
-- body
end
-- 初始值, 终止值, 步长
for i=1, 10, 2 do
print i
end
-- 数组
for k, v in ipairs(table) do
print(k, v)
end
-- 字典
for k, v in pairs(table) do
print(k, v)
end
反向表构造实例:
revDays = {}
for i,v in ipairs(days) do
revDays[v] = i
end
while i<10 do
print i
i = i + 1
end
repeat
print i
i = i + 1
until i < 10
break 语句可用来退出当前循环(for, repeat, while),循环外部不可以使用。
return 用来从函数返回结果,当一个函数自然结束,结尾会有一个默认的return。
Lua语法要求break和return只能出现在block的结尾一句(也就是说:作为chunk的最后一句,或者在end之前,或者else前,或者until前):
local i = 1
while a[i] do
if a[i] == v then break end
i = i + 1
end
首先是最简单的 Lua 为 C/C++ 程序变量赋值,类似史前的 INI 配置文件。
width = 640
height = 480
这样的赋值即设置全局变量,本质上就是在全局表中添加字段。
在 C/C++ 中,Lua 其实并不是直接去改变变量的值,而是宿主程序通过“读取脚本中设置的全局变量到栈、类型检查、从栈上取值”几步去主动查询。
int w, h;
if (luaL_loadfile(L, fname) || // 读取文件,将内容作为一个函数压栈
lua_pcall(L, 0, 0, 0)) // 执行栈顶函数,0个参数、0个返回值、无出错处理函数(出错时直接把错误信息压栈)
error();
lua_getglobal(L, "width"); // 将全局变量 width 压栈
lua_getglobal(L, "height"); // 将全局变量 height 压栈
if (!lua_isnumber(L, -2)) // 自顶向下第二个元素是否为数字
error();
if (!lua_isnumber(L, -1)) // 自顶向下第一个元素是否为数字
error();
w = lua_tointeger(L, -2); // 自顶向下第二个元素转为整型返回
h = lua_tointeger(L, -1); // 自顶向下第一个元素转为整型返回
读取表的字段的操作也是类似,只不过细节上比较麻烦,有点让我想起在汇编里调戏各种寄存器:
score = { chinese=80, english=85 }
int chinese, english;
if (luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0))
error();
lua_getglobal(L, "score"); // 全局变量 score 压栈
lua_pushstring(L, "chinese"); // 字符串 math 压栈
lua_gettable(L, -2); // 以自顶向下第二个元素为表、第一个元素为索引取值,弹栈,将该值压栈
if (!lua_isnumber(L, -1)) // 栈顶元素是否为数字
error();
chinese = lua_tointeger(L, -2);
lua_pop(L, 1); // 弹出一个元素 (此时栈顶为 score 变量)
lua_getfield(L, -1, "english"); // Lua5.1开始提供该函数简化七八两行
if (!lua_isnumber(L, -1))
error();
english = lua_tointeger(L, -2);
lua_pop(L, 1); // 如果就此结束,这一行弹不弹都无所谓了
前面说过,设置全局变量本质就是在全局表中添加字段,所以 lua_getglobal 函数本质是从全局表中读取字段。没错,lua_getglobal 本身就是一个宏:
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s)
宏 LUA_GLOBALSINDEX 指明的就是全局表的索引。