关键字
and break do else elseif
end false for function goto
if in local nil not
or repeat return then true
until while
变量
定义全局变量
msg = "hello world"
定义局部变量
local msg = "hello world"
代码注释
行注释 --
使用 --
可以注释到行尾
块注释 --[[]]
使用 --[[xxx]]
可以注释一个代码块
如果注释内容存在
]]
,则需要配合=
,例如--[=[
会一直匹配到下一个]=]
出现,]]
里可以写多个=
,例如--[==[
会一直匹配到下一个]==]
.
类型
lua有8种类型,分别是:
- Boolean
- number
- string
- userdata
- function
- thread
- table
type函数
使用type函数可以获取变量的类型,例如:
type(nil) --> nil
type(true) --> Boolean
type("Hello world") --> string
type(io.stdin) --> userdata
Boolean
lua中,除了 nil 和 false 为false,其他都为true
number
lua5.3之后,number类型分为 integer 和 float
通过math.type函数可以获取number的类型,例如:
math.type(3) --> integer
math.type(3.0) --> float
操作符
//
lua5.3加入了一个新的操作符,floor division
/
运算符使用是得到一个float类型的数字,哪怕是2个integer相除
如果2个integer用//
相除,会得到一个integer
关系运算符
<
>
<=
>=
==
~=
~=
类似其他语言的!=
,和==
相反.
随机数
random
使用random函数可以生成一个伪随机数
如果random不带参数,随机数分布在[0,1)中.
如果random只带一个参数,则随机数分布在[1,n]中.
如果random带2个参数,随机数分布在[n,n]中.
因为是伪随机数,所以每一次执行程序,随机数都是相同的序列,如果想改变这种情况,可以设置随机数种子,一般设置时间戳为种子.
math.randomseed
设置当前随机数种子,例如设置当前时间戳为随机数种子:
math.randomseed(os.time())
字符串
计算字符串的长度 #
#
符号用来计算字符串的长度
例如
a = "hello"
print(#a) --> 5
拼接字符串 ...
...
可以用来拼接多个字符串,例如:
"Hello " .. "World" --> Hello World
"result is " .. 3 --> result is 3
10 .. 20 --> result is 1020
长字符串
如果一个字符串字面量,非常长,需要写多行,那么可以使用[[]]
符号来创建长字符串.
例如:
page = [[
<html>
<head>
<title>An HTML Page</title>
</head>
<body>
<a href="http://www.lua.org">Lua</a>
</body>
</html>
]]
格式化
lua也有类似c的print函数,例如:
string.format("x = %d y = %d", 10, 20) --> x = 10 y = 20
string.format("<%s>%s</%s>", tag, title, tag) --> <h1>a title</h1>
控制结构
if then else
if用来测试条件,如果为true执行then语句块,否者执行else语句块
if a < 0 then a = 0 end
if a < b then return a else return b end
if line > MAXLINES then
showpage()
line = 0
end
while
while用来执行循环,条件成立则执行do语句块
local i = 1
while a[i] do
print(a[i])
i=i+ 1
end
repeat
和while类似,但是第一次不测试条件,先执行后测试
local line
repeat
line = io.read()
until line ~= ""
print(line)
Numerical for
for需要3个表达式,exp3可以省略,如果exp省略,则lua假设exp3每次+1
for var = exp1, exp2, exp3 do
something
end
break, return, goto
break用来跳出一个循环,return用来跳出一个函数,goto可以跳到某个标签的位置,标签通过 ::xx::
符号定义
while some_condition do
::redo::
if some_other_condition then goto continue
else if yet_another_condition then goto redo
end
some code
::continue::
end
Table
lua中,table是最核心的数据结构,table既不是值,也不是变量,而是一个对象.
创建table
a = {}
k = "x"
a[k] = 10
a[20] = "great"
a["x"] --> 10
k = 20
a[k] --> "great"
语法糖
t["name"] 在lua里 可以写成 t.name
a = {}
a.x = 10 -- same as a["x"] = 10
a.x --> 10
构造器
{}是一个空constructor,constructor可以初始化一个列表
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"}
print(days[4]) --> Wednesday
constructor 也可以初始化一个 record-like table
a = {x = 10, y = 20}
数组,列表,序列
一个table,如果index是一个有序序列,则这个table就是一个数组.
a = {}
a[1] = 1
a[2] = 1
a[3] = 1
a[4] = 1
数组的长度
可以和字符串一样,通过使用#
来获取数组的大小
#a --> 4
数组空洞
如果一个table的index是一个序列,但是其中某些字段为nil,那么通过#
无法计算真实的数组长度
a = {}
a[1] = 1
a[2] = nil -- does nothing, as a[2] is already nil
a[3] = 1
a[4] = 1
#a --> 1
遍历table
使用 pairs iterator 可以用来迭代table
t = {10, print, x = 12, k = "hi"}
for k, v in pairs(t) do
print(k, v)
end
--> 1 10
--> k hi
--> 2 function: 0x420610
--> x 12
pairs iterator是无序的,如果想要保持table赋值的顺序,可以使用ipairs
t = {10, print, 12, "hi"}
for k, v in ipairs(t) do
print(k, v)
end
--> 1 10
--> 2 function: 0x420610
--> 3 12
--> 4 hi
如果table是一个数组,则可以通过#
符号来遍历
t = {10, print, 12, "hi"}
for k = 1, #t do
print(k, t[k])
end
--> 1 10
--> 2 function: 0x420610
--> 3 12
--> 4 hi
Safe Navigation
如果我们想调用table的函数,首先得校验table是否存在.如果table嵌套比较多写起来比较丑,而且麻烦
例如:
zip = company and company.director and
company.director.address and
company.director.address.zipcode
使用 or {} 可以简化这种操作
zip = (((company or {}).director or {}).address or {}).zipcode
或者更简洁高效的写法
E = {} -- can be reused in other similar expressions
zip = (((company or E).director or E).address or E).zipcode
函数
省略括号
如果函数只有一个参数,可以省略掉(),例如:
print "Hello World" <--> print("Hello World")
dofile 'a.lua' <--> dofile ('a.lua')
print [[a multi-line <--> print([[a multi-line
message]] message]])
type{} <--> type({})
实参和形参可以不对称
如果实参多余形参,则抛弃掉多余的实参,如果实参少于形参,则形参初始化为nil
function f (a, b) print(a, b) end
f() --> nil nil
f(3) --> nil nil
f(3, 4) --> 3 4
f(3, 4, 5) --> 3 4 (5 is discarded)
多返回值
一个函数可以有多个返回值
function maximum (a)
local mi = 1
local m = a[mi]
for i = 1, #a do
if a[i] > m then
mi = i; m = a[i]
end
end
return m, mi
end
-- index of the maximum value
-- maximum value
-- return the maximum and its index
print(maximum({8,10,23,12,5})) --> 23 3
多返回值可以初始化一个table
print(maximum({8,10,23,12,5})) --> 23 3 -- returns 2 results
t = {foo2()} -- t = {"a", "b"}
可变参数
函数定义可以通过 ...
符号来声明可变参数
function add (...)
local s = 0
for _, v in ipairs{...} do
s=s+ v
end
return s
end
print(add(3, 4, 10, 25, 12)) --> 54
...
甚至用来初始化变量和作为返回值
function foo (...)
local a, b, c = ...
function id (...) return ... end
table.pack函数
聚合 ...
可以使用{...},也可以使用table.pack函数,{...}有可能存在空洞,而table.pack则可以检测到nil
function nonils (...)
local arg = table.pack(...)
for i = 1, arg.n do
if arg[i] == nil then
return false
end
end
return true
end
print(nonils(2,3,nil)) --> false
print(nonils(2,3)) --> true
print(nonils()) --> true
print(nonils(nil)) --> false
select函数
select函数接收一个固定参数 selector
,加一个可变参数,如果 selector
为n,则返回这个可变参数中n之后的参数,如果 selector
为#
,则返回可变参数的个数
例如:
print(select(1, "a", "b", "c")) --> a b c
print(select(2, "a", "b", "c")) --> b c
print(select(3, "a", "b", "c")) --> c
print(select("#", "a", "b", "c")) --> 3
通过select函数来遍历可变参数
function add (...)
local s = 0
for i = 1, select("#", ...) do
s = s + select(i, ...)
end
return s
end
table.unpack函数
跟table.pack函数相反,跟table.unpack函数是将一个table拆分
print(table.unpack{10,20,30}) --> 10 20 30
a,b = table.unpack{10,20,30} -- a=10, b=20, 30 is discarded
table.unpack函数还可以接收额外的2个参数
print(table.unpack({"Sun", "Mon", "Tue", "Wed"}, 2, 3))
--> Mon Tue
Simple io模型
简单io模型假设存在 current input stream 和一个 current output stream
默认的current input stream 为stdin,默认的 current output stream 为stdout,io.read函数可以用来读取流里面的内容
current streams有 io.input 和 io.output 两个函数用来获取输入输出流,
例如io.input接收一个文件名,用来打开一个文件:
io.input(filename)
io.write函数
io.write可以接收任意个参数,并将它们写到current output stream
io.write(a..b..c)
一种更高效的写法(不拼接字符串)
io.write(a, b, c)
io.read函数
io.read函数从current stream中读取string,参数可以控制读取的内容
参数 | 内容 |
---|---|
"a" | reads the whole file |
"l" | reads the next line (dropping the newline) |
"L" | reads the next line (keeping the newline) |
"n" | reads a number |
num | reads num characters as a string |
t = io.read("a") -- read the whole file
t = string.gsub(t, "bad", "good") -- do the job
io.write(t) -- write the file
Complete I/O 模型
如果需要同时写入多个文件,则需要Complete I/O 模型,io.open用于打开一个文件,类似c里面的open
io.open函数接收一个文件名,后面加一个字符串 mode 参数,类似c,mode可以为
- "r" 读
- "w" 写
- "a" 附加
如果文件不存,或者存在异常,在则返回nil
print(io.open("non-existent-file", "r"))
--> nil non-existent-file: No such file or directory 2
print(io.open("/etc/passwd", "w"))
--> nil /etc/passwd: Permission denied 13
通常检查错误是通过assert断言
local f = assert(io.open(filename, mode))
打开文件之后可以使用read和write读取或者写入,但是是在一个stream对象上操作
例如
local f = assert(io.open(filename, "r"))
local t = f:read("a")
f:close()
实际上io.read是io.input():read的简写,io.write是io.output():write的简写
预设的stream对象
- io.stdin
- io.stdout
- io.stderr
直接使用预设的stream对象
io.stderr:write(message)
如果想更改current stream
local temp = io.input() io.input("newinput") -- save current stream
do something with new input -- open a new current stream
io.input():close() -- close current stream
io.input(temp) -- restore previous current stream
io.lines函数
io.lines函数返回一个重复读取文件的iterator,lua5.2之后,io.lines和io.read接收同样的参数,例如
for block in io.input():lines(2^13) do
io.write(block)
end
执行系统命令
os.execute函数
os.execute可以执行系统命令,例如创建文件夹:
function createDir (dirname)
os.execute("mkdir " .. dirname)
end
os.popen函数
os.popen功能和os.execute类似,但是可以获取命令的返回内容
-- for POSIX systems, use 'ls' instead of 'dir'
local f = io.popen("dir /B", "r")
local dir = {}
for entry in f:lines() do
dir[#dir + 1] = entry
end
网友评论