前情提要:
作用域
以下都属于Lua的块
if x then
stuff()
moreStuff()
end
for i = 1, 10 do
local x = "foo"
end
function foo(x, y)
-- ...
end
-- 显式声明块
do
local x = 3
local y = 4
end
Lua使用词法作用域,每个块都有自己的作用域:
x = 5 -- 全局
function foo()
local x = 6
print(x) -- 6
if x == 6 then
local x = 7
y = 10 -- 全局
print(x) -- 7
end
print(x, y) -- 6, 10
do
x = 3
print(x) -- 3
end
print(x) -- 3
end
foo()
print(x, y) -- 5, 10
块可以写在一行里:
function foo(x) return x * 5 end
if x then print(x) end
do foo() end
函数
参数默认值
Lua不直接支持参数默认值,但是如果一个函数调用的时候没有指明参数,那么该参数就会使用缺省值nil
:
function func(x, y, z)
if not y then y = 0 end
if not z then z = 1 end
-- code
end
用or
更简短:
function func(x, y, z)
y = y or 0
z = z or 1
end
Table语法
只有一个Table参数的函数可以省去括号:
function foo(t)
return t[1] * t.x + t[2] * t.y
end
foo{3, 4, x = 5, y = 6} -- 39
参数数目不定
使用...
即可。
function sum(...)
local ret = 0
for i, v in ipairs{...} do ret = ret + v end
return ret
end
sum(3, 4, 5, 6) -- 18
参数被放置于table{...}
中,除了像上面一样访问外,还可以通过select
函数访问:
function sum(...)
local ret = 0
for i = 1, select("#", ...) do ret = ret + select(i, ...) end
return ret
end
self
table内的函数可以通过下面的方式调用:
t = {}
function t:func(x, y)
self.x = x
self.y = y
end
t:func(1, 1)
print(t.x) -- 1
等价于
function t.func(self, x, y)
self.x = x
self.y = y
end
t.func(t, 1, 1)
结合元表,可以实现面向对象编程。
加载文件
dofile("test.lua")
loadfile("test.lua")()
func = loadfile("test.lua")
func()
上面三种写法是等效的。Lua文件以函数的方式加载,这解释了为什么loadfile
返回一个函数。dofile
在加载文件的同时调用函数。
local message = "Cheese for everyone!"
local t = { 1, 2, 3, 4, 5 }
print(message)
return t
将以上代码保存为cheese.lua
,然后加载:
x = dofile("cheese.lua")
x
会被设定为t
,cheese.lua
中的信息会被打印出来。
包系统
更优雅的方式是使用包系统:
require("cheese")
require("folder.subfolder.file")
require
将.
替换为目录分隔符,在package.path
中查找文件。一旦成功加载,路径会被加入package.loaded
表。require
不会重复加载该表中已有的文件。
执行字符串
使用loadstring
,类似loadfile
,字符串将被编译为函数。
loadstring("print('hello')")()
下一站:Lua小技巧
原文 Lua for Programmers Part 3: More Advanced Concepts
翻译 SegmentFault
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。